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)

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
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 and trade requests live on different status endpoints; polling the wrong one returns this
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 failed during on-chain execution
REQUOTE_FAILEDThe Vault could not re-quote the pool to validate the trade
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_AVAILABLEHardware-wallet signing needs the GUI, which this Vault instance is running without

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)

Admin API

Codes specific to the admin API (default port 4664), used by the CLI and the Vault window itself. Agents never see these.

CodeMeaning
GUI_ONLY_MODE (403)The admin API only accepts commands from the Vault window. Allow other local processes with primer-vault config set admin-api open or --admin-open
UNLOCK_FAILED (401)Wrong wallet password
TOO_MANY_ATTEMPTS (429)Too many failed unlock attempts; wait out the cooldown
MISSING_NAME / MISSING_FIELDS (400)A required field was not provided
UNKNOWN_SETTING (400)No setting by that name
NOT_COMMISSIONED (400)The operation needs a commissioned agent
APPROVAL_FAILED (400)Approving or rejecting the pending request failed
TRADE_FAILED (400)The approved trade failed to execute
CREATE_FAILED / IMPORT_FAILED / DELETE_FAILED / DERIVE_FAILED / RENAME_FAILED (400)The wallet, seed, or address operation failed; the message says why
UPDATE_FAILED (400)Editing the agent failed
MANDATE_FAILED / SET_MANDATE_FAILED / UPLOAD_FAILED (400)Generating, setting, or uploading the agent's mandate failed
WALLET_LOCKED (409)The operation needs the wallet unlocked

The admin API also uses NOT_FOUND, INVALID_JSON, BAD_REQUEST, INTERNAL_ERROR, FOREIGN_HOST_REJECTED and BROWSER_ORIGIN_REJECTED with the same meanings as above.


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.