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.

For agents: platform API errors include a machine-readable 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 token

The 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 expired

The 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 mismatch

The 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 key

The 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 signature

The 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_INVALID

The spending mandate failed verification before the spend was attempted.

Recover: See mandate verification errors above — the .message contains the underlying reason.

LIMIT_EXCEEDED

The 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_ALLOWED

The 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_INVALID

The task mandate failed verification.

Recover: See mandate verification errors — the .message contains the underlying reason.

CAPABILITY_NOT_PERMITTED

The 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_VIOLATION

The 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_REQUIRED

This 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_EXCEEDED

The 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_EXCEEDED

LLM token or web-request budget (computeLimit) is exhausted.

Recover: Same as ACTION_LIMIT_EXCEEDED — budgets are hard stops, not suggestions.

DATA_ACCESS_VIOLATION

The 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_REQUIRED

The 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_EXCEEDED

The 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 409

The 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 400

Request body is not valid JSON.

Recover: Check Content-Type: application/json and body encoding.

INVALID_DIDHTTP 422

DID 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 422

publicKeyB64 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 401

Agent 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 401

Ed25519 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 429

Too many requests from this IP.

Recover: Honor retryAfterSeconds in the response body before retrying.

REGISTRY_UNREACHABLEHTTP 502

The 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 400

Registration requires did, manifestCID, and publicKeyB64.

Recover: Pin your manifest to IPFS first, then register with all three fields.

Invalid or revoked API keyHTTP 401

The 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 409

Another 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 403

Write 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.