> ## Documentation Index
> Fetch the complete documentation index at: https://docs.notareum.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Error codes

# 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

```typescript theme={"system"}
import { Notareum, NotareumError, RegistryError } from "@notareum/sdk";

try {
  await ntm.registry.registerResource(nota);
} catch (e) {
  if (e instanceof RegistryError && e.code === "REG_ALREADY_REGISTERED") {
    // update instead of register
  } else if (e instanceof NotareumError) {
    console.error(e.code, e.message);
  } else {
    throw e;
  }
}
```

### Python

```python theme={"system"}
from notareum import Notareum
from notareum.errors import RegistryError, NotareumError

try:
    ntm.registry.register_resource(nota)
except RegistryError as e:
    if e.code == "REG_ALREADY_REGISTERED":
        ...
except NotareumError as e:
    log.error(e.code, e.message)
```

### Rust

```rust theme={"system"}
use notareum::{Notareum, SdkError};

match ntm.registry.register_resource(0u8, 1u64, identifier, &proof_hash, alias).await {
    Ok(tx) => { /* ... */ }
    Err(SdkError::Contract { reason, .. }) if reason == "REG_ALREADY_REGISTERED" => {
        /* update instead */
    }
    Err(e) => return Err(e.into()),
}
```

## Related pages

* [Glossary](glossary.md)
* [FAQs](faqs.md)
* [SDK Overview](../sdks/overview.md)
* [Smart Contracts Overview](../smart-contracts/overview.md)
