Error Reference
Every error the protocol and platform can return, what it means, and how to recover. Constraint violations are not bugs — they are the mandate system working as designed.
code field. SDK exceptions expose .code on the error object. Match on codes, not messages — messages may change, codes will not.Mandate verification
verifyMandate() / verifyTaskMandate() — returned as { valid: false, reason }
Malformed tokenThe mandate token could not be decoded — truncated, corrupted, or not a mandate token at all.
Recover: Check you are passing the token string exactly as returned by issue*Mandate. Do not re-encode or trim it.
Mandate expiredThe mandate's expiry timestamp has passed. Mandates are short-lived by design (default: minutes).
Recover: Issue a fresh mandate. Do not extend TTLs as a workaround — short expiry is the security model.
Mandate grantee mismatchThe mandate was issued to a different DID than the one presenting it.
Recover: Verify you are passing the correct expectedGrantee. A mandate is bound to exactly one grantee DID.
Mandate was signed with a since-rotated keyThe grantor rotated their keypair after signing this mandate — the old key is revoked.
Recover: Request a new mandate signed with the grantor's current key. Fetch the latest key from the registry.
Invalid signatureThe Ed25519 signature does not verify against the grantor's public key.
Recover: Confirm you fetched the right grantor public key (check keyVersion on the registry record). Never accept an unverified mandate.
Spending constraint violations
SpendingConstraintViolation — thrown with .code
MANDATE_INVALIDThe spending mandate failed verification before the spend was attempted.
Recover: See mandate verification errors above — the .message contains the underlying reason.
LIMIT_EXCEEDEDThe attempted charge exceeds the mandate's spendLimitUsd. Enforced cryptographically — cannot be bypassed.
Recover: Request a mandate with a higher limit from the human issuer, or reduce the transaction amount.
MERCHANT_NOT_ALLOWEDThe mandate restricts spending to specific merchant DIDs and this merchant is not on the list.
Recover: Check mandate.constraints.allowedMerchants. Request a mandate that includes this merchant.
Task constraint violations
TaskConstraintViolation — thrown with .code
MANDATE_INVALIDThe task mandate failed verification.
Recover: See mandate verification errors — the .message contains the underlying reason.
CAPABILITY_NOT_PERMITTEDThe capability being invoked is not in the mandate's allowed list (or is explicitly blocked).
Recover: Check mandate.constraints.allowed / blocked. Request a mandate covering this capability.
REVERSIBILITY_VIOLATIONThe mandate has reversibleOnly: true and this capability has irreversible side effects.
Recover: Either use a reversible alternative, or ask the issuer for a mandate without reversibleOnly.
HUMAN_GATE_REQUIREDThis capability is listed in humanGates — execution pauses until the human approves.
Recover: Not an error to retry. Surface the approval_required event to the user and resume via POST /v1/resume after approval.
ACTION_LIMIT_EXCEEDEDThe per-capability invocation budget (actionLimits) is spent.
Recover: The task is over-budget by design. Complete with what you have, or request a mandate with higher limits.
COMPUTE_LIMIT_EXCEEDEDLLM token or web-request budget (computeLimit) is exhausted.
Recover: Same as ACTION_LIMIT_EXCEEDED — budgets are hard stops, not suggestions.
DATA_ACCESS_VIOLATIONThe task attempted to access a data scope not granted by the mandate.
Recover: Check mandate.constraints.dataAccess. Request broader scope from the issuer if genuinely needed.
SANDBOX_REQUIREDThe mandate requires execution inside a sandbox and the runtime is not sandboxed.
Recover: Run the task in a sandboxed executor, or request a mandate without the sandbox requirement.
DELEGATION_DEPTH_EXCEEDEDThe mandate chain is deeper than maxDelegationDepth allows — an agent tried to sub-delegate too far.
Recover: Flatten the delegation chain. Depth limits prevent runaway agent-spawns-agent recursion.
Spending ledger
Registry API /v1/spending — BudgetExhaustedError
BUDGET_EXHAUSTEDHTTP 409The parent mandate's budget pool has no room for this allocation. Prevents an orchestrator holding a $500 mandate from issuing N children each claiming $500.
Recover: Release unused child allocations first, or the parent budget is genuinely spent.
Platform API
www.aroha-labs.com/api/* — returned as { error, code }
INVALID_JSONHTTP 400Request body is not valid JSON.
Recover: Check Content-Type: application/json and body encoding.
INVALID_DIDHTTP 422DID missing or does not match did:aroha:<name> format.
Recover: DIDs must match /^did:aroha:[a-z0-9][a-z0-9:._-]+$/i.
INVALID_PUBLIC_KEYHTTP 422publicKeyB64 is not a base64-encoded 32-byte raw Ed25519 public key.
Recover: Export the raw (not PEM/PKCS8) public key and base64-encode it.
CHALLENGE_INVALIDHTTP 401Agent key challenge failed — expired, tampered, or issued for a different DID/key.
Recover: Request a fresh challenge (they expire after 5 minutes) and retry within the window.
SIGNATURE_INVALIDHTTP 401Ed25519 signature over the challenge string does not verify.
Recover: Sign the exact challenge string (UTF-8 bytes) with the private key matching publicKeyB64.
RATE_LIMITEDHTTP 429Too many requests from this IP.
Recover: Honor retryAfterSeconds in the response body before retrying.
REGISTRY_UNREACHABLEHTTP 502The platform could not reach the registry service.
Recover: Transient — retry with backoff. Check /api/status for platform health.
Registry API
aroha-registry.aroha-labs.workers.dev/v1/*
Missing required fieldsHTTP 400Registration requires did, manifestCID, and publicKeyB64.
Recover: Pin your manifest to IPFS first, then register with all three fields.
Invalid or revoked API keyHTTP 401The Bearer key is unknown, revoked, or malformed.
Recover: Create a key via /keys (signed in) or the agent-request flow, and send it as Authorization: Bearer <key>.
DID already registeredHTTP 409Another record owns this DID.
Recover: DIDs are globally unique. Choose a different DID, or update your existing record with your owner key.
Not your agentHTTP 403Write attempted with a different API key than the one that registered the agent.
Recover: Writes are scoped to the registering key. Use the original key, or re-register under a new DID.
Still stuck?
Check platform status for live service health, or ask in Discord — include the error code and your correlationId.