Skip to content

Every error code, and what to do about it

Every error code the service returns, grouped by status, with what to do about each.

Updated View as Markdown

Every error from every route has one shape:

{
  "error": {
    "code": "account_not_found",
    "message": "…",
    "status": 404,
    "requestId": "…"
  }
}

Branch on error.code. Messages are written for humans and may change; codes are the contract. Keep requestId when reporting a problem — it comes back as the x-request-id response header too, and it is what your operator will ask for.

Some errors carry a fifth field, error.details, naming the specific thing that failed:

{
  "error": {
    "code": "scope_denied",
    "message": "…",
    "status": 403,
    "requestId": "…",
    "details": { "required": "sign" }
  }
}
Code details
scope_denied required — the scope the route wanted
invalid_slug expected — the grammar it wanted
account_locked account
rpc_not_configured network
session_capacity_exceeded, rpc_capacity_exceeded scope and limit — which ceiling you hit, and what it is
mint_rate_limited, account_unlock_rate_limited, workspace_creation_rate_limited, workspace_recreation_cooldown retryAfterSec

Treat details as present-or-absent: no other code carries it, and nothing outside this table is exposed.

Wait exactly as long as you are told

Every 429 that knows its own deadline sets a Retry-After response header, in seconds. That covers the four rate-limit codes above. Read the header rather than guessing at a backoff — it is the authoritative answer, and for workspace_recreation_cooldown a guess will be badly wrong.

The two capacity codes, session_capacity_exceeded and rpc_capacity_exceeded, do not set it: their ceilings clear when other work finishes, not on a clock. Those are the ones to back off exponentially.

400 — the request was malformed

Code Meaning and fix
invalid_body The JSON shape or field combination is wrong. The message names the expected shape.
invalid_slug A workspace or account identifier has invalid syntax. Lowercase letters, digits, hyphens; starts alphanumeric.
invalid_parameter A path or query selector is malformed — for example ?force= or ?vm= with an unaccepted value.
invalid_mnemonic The supplied mnemonic could not be parsed.
invalid_private_key The supplied private key could not be parsed.
unsupported_network The signing engine cannot work with that network. Note this is not what a route’s ?network= selector returns for a network the workspace lacks — that is a 404 account_not_found.
rpc_endpoint_rejected The RPC URL you tried to register was refused at admission.

401 — you are not authenticated

Code Meaning and fix
bad_api_key X-Api-Key or X-Api-Secret is missing or wrong.
bad_password The workspace password is wrong.
session_expired The idle or absolute clock elapsed. Mint a new token and retry — this is routine, not exceptional.

403 — authenticated, but not allowed

Code Meaning and fix
scope_denied The token is valid but lacks the scope. Re-mint with the scope you need.
permission_denied The operation is not permitted for this caller.
export_disabled No exportPublicKey is registered for the tenant. Your operator must register one.

404 — no such thing

Code Meaning and fix
workspace_not_found No workspace with that slug for this tenant.
account_not_found No such account, wallet, address, or network in this workspace.
not_found The route or resource does not exist.

409 — conflicts with current state

Code Meaning and fix
workspace_exists That slug is already in use.
workspace_in_use A session is open. Retry with ?force=true if revoking it is intended.
quota_workspaces_exceeded Tenant workspace limit reached.
quota_wallets_exceeded Tenant wallet limit reached.
rpc_not_configured No usable endpoint for that network. Register one, or ask your operator.
tx_dropped The transaction was dropped before inclusion.
tx_aborted Submission was aborted before it completed.

422 — well formed, but cannot be done

Code Meaning and fix
unsupported_for_kind The account, wallet, or chain type cannot perform this otherwise valid operation — typed data on a non-EVM address, a mnemonic from a PK account, a VM the wallet lacks.
weak_password The password is shorter than 12 characters. Length is the only rule — no character-class requirement applies. Raised when creating a workspace or an own-password account, never when minting a token.
tx_build_failed The transaction could not be constructed from the supplied fields.

423 — locked

Code Meaning and fix
workspace_locked The workspace is not open. Mint a token.
account_locked The account is not currently open. Call the unlock route with the account’s password — or, for an account that shares the workspace password, with the workspace password. Any account reaches this state once its custody window expires, not only one created with hasOwnPassword.
record_locked A record is held by another operation. Retry shortly.

429 — slow down, or you are at capacity

Code Meaning and fix
mint_rate_limited Too many token mints for this tenant. Back off.
account_unlock_rate_limited Too many failed account-unlock attempts.
workspace_creation_rate_limited Creating workspaces too quickly.
workspace_recreation_cooldown That slug was recently deleted and is still cooling down.
session_capacity_exceeded Too many workspaces held open at once. Revoke a token you no longer need.
rpc_capacity_exceeded Too many concurrent chain operations. Retry with backoff.

500 — the service failed

Code Meaning and fix
storage_error A storage operation failed.
encrypt_failed Encryption failed.
decrypt_failed Decryption failed.
algorithm_irreversible The requested transformation cannot be reversed.
tx_sign_failed Signing did not produce a usable transaction.

These are not your fault and not fixable by retrying the same request. Capture requestId and report it.

501 — not implemented

Code Meaning and fix
not_implemented The route exists but is not available in this release — see Addresses.
unsupported_operation The operation is not supported by the underlying engine.

502, 504, 507 — upstream and capacity

Status Code Meaning and fix
502 rpc_unreachable The RPC endpoint did not respond or answered non-2xx.
502 rpc_rejected The endpoint responded with a refusal.
502 tx_submit_failed The endpoint explicitly refused the submission.
504 tx_timeout Submission timed out. Check transaction status before resending.
507 disk_full The service is out of storage.

Retry guidance

Situation Retry?
429 with a Retry-After header Yes, after exactly that long
429 without one Yes, with exponential backoff
session_expired Yes, after minting a new token
rpc_unreachable, rpc_rejected Yes, with backoff; consider a different endpoint
tx_timeout, or send returning unknown Not on found: false alone — that cannot distinguish “never sent” from “in the mempool”. See Send transactions
record_locked Yes, shortly
Any 400, 403, 404, 422 No — fix the request
500-class No — report with requestId

Codes from outside the catalog

The codes above are the service’s own, and each one names a specific condition. A few others come from the layer in front of it, before a request ever reaches a route:

Status Code When
400 bad_request The JSON body could not be parsed at all
401 unauthorized A rejection with no more specific code
403 forbidden A rejection with no more specific code
404 not_found No such route — as distinct from no such record
413 payload_too_large The request body exceeded the parser’s limit, roughly 100 KB
500 internal_error An unhandled failure. Capture requestId and report it
request_failed A 4xx with no more specific code

They carry the same envelope as everything else, so branching on error.code still works — but they are generic by construction, and error.details is never present on them.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close