Documentation

Error Code Reference

Every error code the Vault can return, what it means, and what to do about it.

How errors look

Every error response from the Vault is JSON with a human-readable error message and a machine-readable code:

{
  "status": "error",
  "error": "Would exceed daily limit",
  "code": "EXCEEDS_DAILY_LIMIT"
}

The HTTP status of the response tells you the kind of failure; the code tells you the exact cause. As a rule of thumb:

HTTP statusWhat it meansWhat to do
400The request itself is wrongFix the request before retrying
401Authentication failedCheck credentials and signature
403Understood, but refusedRetrying unchanged will not help
404The thing referenced does not existCheck the identifier
409Conflicts with current stateStart over with a fresh request
429A limit that clears on its ownBack off and retry later
500Something failed on the Vault's sideThe request was fine; retrying is reasonable
503Temporarily unavailableOften user-fixable in the app (unlock wallet, reconnect device); retry after

Agent API

Codes returned by the agent-facing API (default port 4663): the /sign, /trade, /callback, /mandate and status endpoints.

400 — Malformed request

CodeMeaning
INVALID_JSONThe request body is not valid JSON
INVALID_CONTENT_LENGTHThe Content-Length header is missing or invalid
MISSING_AGENT_IDNo agent_id in the request
MISSING_SIGNATURENo signature in the request
MISSING_TRADE/trade called without a trade object
MISSING_REQUEST_ID / INVALID_REQUEST_IDStatus poll without a request id, or with a malformed one
MISSING_TRANSACTION_ID / INVALID_TRANSACTION_IDTransaction lookup without a transaction id, or with a malformed one
MISSING_EVENT / INVALID_EVENT/callback without an event, or with one that is not a recognized value
MISSING_TX_HASH / INVALID_TX_HASHSettlement callback without an on-chain transaction hash, or with a malformed one
MISSING_X402_DATAPayment request without the x402 payment data
INVALID_X402_DATA / INVALID_X402_FORMATThe x402 payment data does not parse or is not in a supported format
INVALID_X402_RESPONSE / INVALID_RESPONSE_STATUSReserved for x402 response validation (not currently emitted)
INVALID_PAYMENT_REQUIREDThe 402 Payment Required data forwarded by the agent is invalid
INVALID_PAYMENT_DATAPayment fields fail validation
FIELD_NOT_PERMITTEDThe trade includes a field the agent may not set (agent_id, wallet_address, recipient) — the Vault takes these from the authenticated credentials
BAD_REQUESTThe trade object fails shape validation
INVALID_REQUESTGeneric malformed request
ERRORGeneric fallback when no more specific code applies

401 — Authentication failed

AUTH_FAILEDThe bearer token or HMAC signature did not verify. Check the token, the signed message shape, and clock skew (HMAC timestamps have a replay window). For an HMAC agent, a locked wallet also answers AUTH_FAILED rather than WALLET_LOCKED — the shared secret needed to check the signature is itself encrypted, so Vault cannot tell "wrong signature" from "wallet locked" without unlocking first for a caller it has not yet verified, and revealing that distinction would let anyone poll for whether the wallet happens to be open. Bearer agents, whose token is checked before the wallet is touched, get the honest WALLET_LOCKED code instead (see below). If every request from an otherwise-correctly-configured HMAC agent fails, check whether the wallet is unlocked in the app.

403 — Refused by policy or configuration

Retrying the same request will not help; either the request must change or the user must change the policy.

CodeMeaning
UNAUTHORIZEDThe agent is not allowed to access this resource (e.g. another agent's transaction)
AGENT_SUSPENDEDThe user has suspended this agent
AGENT_NOT_COMMISSIONEDThe agent is registered but not commissioned with a policy and address
ADDRESS_NOT_COMMISSIONEDThe wallet address the agent is tied to is no longer commissioned
NETWORK_DISABLEDThe requested chain is disabled in Vault settings
NETWORK_NOT_ALLOWED_BY_POLICYThe requested chain is excluded by the agent's policy
X402_DISABLEDx402 payments are switched off in the agent's policy
DOMAIN_NOT_ALLOWEDThe payee's domain is not on the policy's allowlist
DOMAIN_URL_REQUIREDThe policy restricts payees by domain, but the request carried no URL to check
UNSUPPORTED_ASSETThe payment asset is not one the Vault supports
EXCEEDS_PER_REQUEST_MAXThe amount is over the policy's per-request maximum. Permanent for this request — split it into smaller ones
POLICY_REJECTEDA trade was refused by the policy at approval or execution time
DEFI_DISABLED / DEFI_NOT_CONFIGUREDMorpho lending is switched off, or not configured, in the agent's policy
VENUE_NOT_PERMITTEDThe named vault or market is not one the policy's trusted curator stands behind (or the curator changed since the request was made)
EXPOSURE_EXCEEDEDThe deposit would put more at risk than the policy's exposure limit allows
EXPOSURE_UNREADABLECurrent on-chain exposure could not be read, so it cannot be confirmed within limits; treated as a refusal rather than assumed safe
LEDGER_REJECTEDThe user declined the signature on their hardware wallet
FOREIGN_HOST_REJECTEDThe request came from another machine; the API serves localhost only (unless --allow-lan)
BROWSER_ORIGIN_REJECTEDThe request came from a web page; browser calls are refused

404 — Not found

AGENT_NOT_FOUND / UNKNOWN_AGENTNo agent with that id (it may have been deleted)
POLICY_NOT_FOUNDThe agent's policy no longer exists
AGENT_OR_POLICY_MISSINGThe agent or its policy has been removed since the request was made
TRANSACTION_NOT_FOUNDNo transaction with that id
REQUEST_NOT_FOUNDNo pending request with that id. Note that payment, trade and lending requests live on different status endpoints; polling the wrong one returns this. While a trade or lending request is actually being approved, its status reads executing rather than 404, so this code means the id genuinely does not exist
ADDRESS_NOT_FOUNDThe referenced wallet address does not exist
NOT_FOUNDThe URL path does not match any endpoint, or the resource does not exist

405 / 413 — Transport-level rejections

METHOD_NOT_ALLOWEDWrong HTTP method for this endpoint (the Allow header lists valid ones)
PAYLOAD_TOO_LARGERequest body over the 1 MB limit

409 — Conflicts with current state

The request was fine when made, but the world has moved. Start over with a fresh request rather than retrying this one.

REQUEST_ALREADY_PROCESSEDThis approval request was already approved or rejected
PAYMENT_ALREADY_SETTLEDThis payment already settled on-chain; use an idempotency_key for a fresh payment
REQUEST_EXPIREDThe approval window closed before the user acted; submit a new request
PRICE_MOVEDThe market moved past the slippage tolerance while the trade awaited approval; re-quote and resubmit
TRADE_NO_LONGER_VALIDThe trade could not be revalidated at approval time

429 — Limits that clear on their own

Nothing about the request is wrong; waiting is the remedy.

RATE_LIMIT_EXCEEDEDToo many requests in a short window
EXCEEDS_DAILY_LIMIT / LIMIT_REACHEDThe policy's daily spending limit is used up; it renews at local midnight, once at least 20 hours have passed since the last renewal
TOO_MANY_PENDINGToo many requests from this agent already await user approval

500 — Failed on the Vault's side

The request was acceptable; something went wrong executing it. Resending unchanged is reasonable.

SIGNING_ERRORSigning failed unexpectedly
EXECUTION_ERRORA trade or lending operation failed during on-chain execution
REQUOTE_FAILEDThe Vault could not re-quote the pool or venue to validate the request
INSUFFICIENT_LIQUIDITYA Morpho withdrawal asked for more than the venue can currently free. Retryable — the venue may be able to free more once other borrowers repay
APPROVAL_REVERTED / REVERTEDThe ERC-20 approval, or the supply/withdraw itself, reverted on-chain
RPC_REJECTEDThe node refused the transaction before ever broadcasting it (insufficient gas, a stale nonce). Nothing was sent
NO_WALLET_PROVIDER / NO_WALLETNo wallet is loaded in the Vault
NO_WALLET_ADDRESSThe wallet has no address to trade or sign from
SDK_NOT_FOUNDA required signing dependency is not installed
LEDGER_ERRORThe hardware wallet returned an unexpected error
LEDGER_NO_SIGNATUREThe hardware wallet returned no signature
INTERNAL_ERRORUnexpected internal failure; details are in the Vault log

503 — Temporarily unavailable

Usually fixable by the user in the Vault app; retry once fixed.

SERVICE_NOT_READYThe Vault is starting up or the service is not running
WALLET_LOCKEDThe wallet is locked; the user must unlock it in the app
WALLET_ADDRESS_NOT_FOUNDThe agent's address is not in the currently unlocked wallet; the user likely has the wrong wallet open
LEDGER_DISCONNECTEDThe hardware wallet is unplugged or asleep
LEDGER_SIGN_NOT_AVAILABLENothing on this Vault instance is registered to prompt for a hardware confirmation. Both editions support Ledger signing normally; this fires only in an unusual composition where no prompt handler was wired up

Codes on successful responses

Two codes ride along on non-error responses to add detail:

APPROVAL_REQUIRED (202)Accompanies status pending: the user must approve in the app; poll the status endpoint
ALREADY_SIGNED (200)Accompanies status success: the payment was signed earlier (the header is no longer cached)

Command Errors

Codes specific to running a command — Vault Terminal, or Desktop's File → Console panel. These never reach an agent; they are what you see typing at a prompt, not what the HTTP API returns.

CodeMeaning
UNLOCK_FAILEDWrong wallet password
TOO_MANY_ATTEMPTSToo many failed unlock attempts; wait out the cooldown
MISSING_NAME / MISSING_FIELDSA required field was not provided
UNKNOWN_SETTINGNo setting by that name
NOT_COMMISSIONEDThe operation needs a commissioned agent
APPROVAL_FAILEDApproving or rejecting the pending request failed
TRADE_FAILEDThe approved trade failed to execute
CREATE_FAILED / IMPORT_FAILED / DELETE_FAILED / DERIVE_FAILED / RENAME_FAILEDThe wallet, seed, or address operation failed; the message says why
UPDATE_FAILEDEditing the agent failed
MANDATE_FAILED / SET_MANDATE_FAILED / UPLOAD_FAILEDGenerating, setting, or uploading the agent's mandate failed
WALLET_LOCKEDThe operation needs the wallet unlocked

Client-side codes

The bundled Python client (CoreClient) raises errors carrying a code. Two are synthesized by the client itself and never sent by the server:

HTTP_ERRORThe server returned an error the client could not parse as JSON
ERRORDefault when no code is available

The authoritative machine-readable list is ERROR_CODE_TO_HTTP_STATUS in src/primer_vault/services/server.py in the Vault repository. If a code you encounter is not on this page, that map is the place to check first.