Skip to main content

Error Codes

Every error surfaced by the Notareum contracts and SDKs has a stable identifier. The identifier is the Solidity custom-error name on-chain and the equivalent typed error class in each SDK. This page groups the full error surface by category with cause, resolution, and the contract or SDK module that raises it.

Conventions

  • Contract errors are Solidity custom errors; they bubble up through the SDK as typed subclasses of NotareumError.
  • SDK-only errors (parsing, signature, transport) are typed SDK classes; they never touch the chain.
  • Every error carries a machine-readable code (uppercase_snake_case) that is stable across SDK versions.
  • Error codes in this page are grouped by category prefix: NOTA_PARSE_*, NOTA_SIG_*, REG_*, VER_*, STAKE_*, GOV_*, FEE_*.

Parsing errors (SDK)

Raised during ntm.nota.parse(raw) or ntm.nota.validate(nota).

NOTA_PARSE_NOT_JSON

Input is not valid JSON. Resolution. Confirm the payload is the full .nota content, not a truncated or base64-wrapped form. Use ntm.nota.decode(raw) first if the input is base64.

NOTA_PARSE_UNSUPPORTED_VERSION

Schema version is unknown to the SDK. Resolution. Upgrade the SDK to a version that supports the schema version in the file, or ask the issuer to produce a .nota with the currently supported schema.

NOTA_PARSE_MISSING_FIELD

Required field absent (resource, issuer, signature, or a sub-field of those). Resolution. The .nota was constructed incorrectly. Regenerate with the fluent builder, which enforces schema at build time.

NOTA_PARSE_BAD_CHAIN

chainId and chainName do not match the SDK’s canonical registry. Resolution. Use the SDK’s chainIdToName / chainNameToId helpers to produce the canonical pairing; do not hand-build these fields.

NOTA_PARSE_IDENTIFIER_FORMAT

identifier does not satisfy the format expected for the resource type and chain (e.g., an EVM address that is not 42 hex characters). Resolution. Normalize the identifier at creation; the builder’s validate() step catches this before signing.

Signature errors (SDK)

Raised by validate() during signature verification.

NOTA_SIG_BAD_ALGORITHM

Signature algorithm is not recognized or not valid for the resource’s chain family. Resolution. Use the SDK’s default signer helper; custom signers must declare the correct algorithm field (ecdsa-secp256k1, ed25519, schnorr-secp256k1).

NOTA_SIG_VERIFY_FAILED

Signature does not verify against the canonical serialization under the declared signer key. Resolution. Ensure the canonical serialization matches the signing implementation. Do not post-process the JSON between sign and ship. Use ntm.nota.canonicalize() explicitly if producing the payload externally.

NOTA_SIG_EXPIRED

The signature’s validFrom/validUntil window does not contain now. Resolution. Re-issue a fresh .nota. Payment requests and deposit addresses carry short validity windows for replay protection.

NOTA_SIG_REVOKED_KEY

The signing key has been revoked in the issuer’s DID document or via NotaRegistry. Resolution. Reject the .nota. Request a fresh one signed by a current key.

NOTA_SIG_ISSUER_MISMATCH

Recovered signer does not match any key declared for the issuer DID. Resolution. Verify the DID document and the declared signerKeyId. This error commonly indicates impersonation.

Registry errors (contract + SDK)

Raised by NotaRegistry calls.

REG_ALREADY_REGISTERED

A resource with the same (type, chainId, identifier) triple exists. Resolution. Use updateResource if the caller owns the existing record; otherwise, the identifier is taken and cannot be reused.

REG_NOT_FOUND

Resource ID does not map to any record. Resolution. Confirm the ID was computed correctly with computeResourceId. Confirm the resource has been registered on the correct network.

REG_NOT_OWNER

Caller is not the owner of the targeted resource. Resolution. The caller must hold the owner address recorded at registration, or transferOwnership must be performed by the current owner first.

REG_ALIAS_TAKEN

Alias is already bound to another, non-revoked resource. Resolution. Choose a different alias, or wait for the current owner to revoke and release.

REG_INVALID_ALIAS

Alias fails validation (length, allowed characters, reserved names). Resolution. Aliases must satisfy [a-z0-9.-]{1,63} after NFC/case normalization.

REG_REVOKED

The targeted resource is revoked. Resolution. Revoked resources are terminal for their ID; re-register with a different identifier or reach out to the owner.

REG_PAUSED

Registry operations are paused by PROTOCOL_ADMIN. Resolution. Wait for unpause (24-hour delay). For production integrations, subscribe to Paused / Unpaused events to gate user flows.

Verification errors (contract + SDK)

Raised by VerificationEngine.

VER_ALREADY_OPEN

A non-expired verification request exists for the resource. Resolution. Wait for the existing request to finalize or expire, then request again.

VER_NOT_VALIDATOR

Attester is not registered in ValidatorStaking or below Basic minimum. Resolution. Stake at least 10,000 NOTA to become an active validator. Use ntm.staking.isActive(addr) to confirm state.

VER_TIER_TOO_LOW

Validator’s tier is below the minimum for the target level (Professional for Enhanced, Enterprise for Institutional). Resolution. Increase stake to reach the required tier, or refrain from attesting requests above your eligible level.

VER_DOUBLE_ATTEST

Validator has already submitted an attestation for this requestId. Resolution. Attestations are single-shot per request; changes of mind are not supported within a round. File a dispute after finalization if the outcome is wrong.

VER_DEADLINE_PASSED

Request deadline has elapsed; no further attestations accepted. Resolution. The request will be finalized as expired or rejected. The requester can open a new request and will receive a partial fee refund.

VER_DAILY_CAP

Validator has exceeded their tier’s daily attestation cap. Resolution. Wait for the daily window to reset, or upgrade tier to increase the cap.

VER_NOT_FINALIZABLE

Quorum conditions are not met for finalizeRequest. Resolution. Poll request state; finalize only after attestCount >= required and the approval ratio threshold is met.

VER_DISPUTE_WINDOW_CLOSED

Attempted to open a dispute after the window expired. Resolution. Disputes must be opened within 24h (Basic), 48h (Enhanced), or 72h (Institutional) of finalization.

VER_INVALID_BOND

Dispute bond below the required amount for the request’s level. Resolution. Pay the exact bond returned by ntm.fee.quote(OpKind.DisputeBondX).

Staking errors (contract + SDK)

Raised by ValidatorStaking.

STAKE_BELOW_MIN

Resulting bonded stake would be below the Basic tier minimum (10,000 NOTA). Resolution. Stake at least the minimum; the contract rejects partial-registration attempts.

STAKE_COOLDOWN_ACTIVE

withdrawPending called before unstakeUnlockAt. Resolution. Wait for cooldown. The SDK exposes ntm.staking.getValidator(addr).unstakeUnlockAt to check.

STAKE_NOTHING_TO_CLAIM

claimRewards called with zero accrued rewards. Resolution. Accrue rewards by submitting attestations or staking-yield epochs before claiming.

STAKE_FROZEN

Validator is frozen by SlashingManager due to Collusion or Double-signing slash. Resolution. Wait for the freeze window (default 30 days). The freeze expiry is observable via isActive(addr) and associated events.

STAKE_NO_ALLOWANCE

NOTA allowance is insufficient for stake(amount). Resolution. approve NOTA to the staking contract, or use stakeWithPermit with an EIP-2612 signature.

Governance errors (contract + SDK)

Raised by veNOTA and AccessManager.

GOV_LOCK_EXISTS

createLock called while an active lock exists. Resolution. Use increaseLockAmount and/or extendLock to modify the existing lock; veNOTA is one-lock-per-address.

GOV_LOCK_NOT_FOUND

Modify or withdraw on a non-existent lock. Resolution. Create a lock first with createLock.

GOV_LOCK_EXPIRED

increaseLockAmount on an expired lock (no remaining voting power). Resolution. withdraw the expired lock and create a new lock with a fresh expiry.

GOV_DURATION_OUT_OF_RANGE

Lock duration below 1 week or above 4 years. Resolution. Choose a duration within [1 week, 4 * 365 days]. The SDK normalizes durations to the nearest weekly epoch.

GOV_ROLE_DENIED

AccessManager denied the call because the caller lacks the required role. Resolution. The function requires a specific role at the declared delay; only pre-authorized governance executors can call.

GOV_DELAY_NOT_ELAPSED

Scheduled operation executed before its eta. Resolution. Wait for the eta timestamp. Use schedule() correctly and record the operationId.

Fee errors (contract + SDK)

Raised by FeeManager.

FEE_UNAUTHORIZED_CALLER

Caller is not a pre-wired protocol contract (NotaRegistry, VerificationEngine, SlashingManager). Resolution. Only the protocol contracts invoke collect/refund; user code pays fees via those flows, not by calling FeeManager directly.

FEE_INSUFFICIENT_PAYMENT

NOTA balance + allowance below the quoted fee. Resolution. Approve at least ntm.fee.quote(op) in NOTA before the operation, or use the permit path.

FEE_SPLIT_INVALID

setSplit called with basis points that do not sum to 10000. Resolution. Governance proposal must set exactly 10000 bps across treasuryBps + burnBps + validatorPoolBps.

FEE_EXCEEDS_CAP

setFeeTable called with a fee above the absolute cap. Resolution. Adjust the proposal to stay within the governance-set caps. Caps are raised via separate proposals if needed.

FEE_ZERO_ADDRESS

setTreasury or setValidatorPool called with address(0). Resolution. Provide a non-zero destination. Burn-only flows use address(0xdead) by convention.

Error handling patterns

TypeScript

Python

Rust