category, code, and message. Errors in the flow category also include a requiredAction — a specific instruction for what the caller should do next.
The contract is identical across the REST API, MCP tools, and the SDK — only the wrapper around it differs. Agents and integrators can recover programmatically instead of guessing.
Error Format
flow errors, a requiredAction is always included:
Error Categories
| Category | Where it appears | Meaning | What the caller should do |
|---|---|---|---|
validation | SDK + MCP | Bad input — address format, missing field, invalid amount | Fix the input and retry |
upstream | SDK + MCP | Backend API or RPC failure, possibly transient | Retry with exponential backoff |
flow | MCP only | Prerequisite missing — OWS wallet not found, signing not configured | Execute the requiredAction first, then retry |
auth | SDK + MCP | API key invalid, missing, or unauthorized | Stop — tell the user to configure credentials |
limit | SDK + MCP | Rate or quota exceeded | Back off, retry after the rate limit window |
not_available | SDK + MCP | Feature not enabled for this API key | Inform the user the feature is not on their plan |
Common Error Codes
Every error carries acode. The Source column tells you which layer raised it — and which surfaces can see it:
- API — returned by the WalletSuite REST API. Visible to SDK and MCP callers alike.
- MCP — raised by MCP tool orchestration (OWS vault, policy engine, Zod pre-validation, tool dispatch). Not returned by the REST API — SDK callers do not encounter these.
Validation Errors
| Code | Source | When It Happens |
|---|---|---|
INVALID_ADDRESS | MCP | Address fails Zod format check for the specified chain (e.g., not 0x-prefixed for EVM) — raised before the API call |
INVALID_AMOUNT | MCP | Human-readable amount is not a positive decimal string |
INVALID_AMOUNT_WEI | MCP | Wei amount is not a positive integer string |
MISSING_TOKEN_CONTRACT | MCP | Token transfer attempted with a symbol but no contract address — use resolve_asset first |
INVALID_PARAMS | MCP | Zod schema validation failed on tool input |
BAD_REQUEST | API | Backend returned 400 — check the request parameters |
NOT_FOUND | API | Backend returned 404 — the resource does not exist |
Flow Errors — MCP only
Flow errors signal prerequisites missing in the local OWS vault, policy engine, or MCP environment. They are raised by MCP orchestration and never returned by the REST API, so SDK callers do not encounter them.| Code | When It Happens | Required Action |
|---|---|---|
OWS_WALLET_NOT_FOUND | Named wallet does not exist in the vault | Create the wallet with create_wallet |
OWS_ACCOUNT_NOT_FOUND | Wallet exists but has no account for the requested chain | Check supported chains or create a new wallet |
OWS_REQUIRED | Sign/broadcast tool called without OWS enabled | Set OWS_ENABLED=true and configure OWS |
OWS_POLICY_DENIED | Policy rejected the signing request | Modify the policy or use a different wallet/chain |
OWS_RPC_URL_REQUIRED | send_transaction called without the chain RPC URL | Set OWS_ETHEREUM_RPC_URL or OWS_TRON_RPC_URL |
OWS_CREDENTIAL_INVALID | Passphrase or agent token cannot unlock the vault | Check credentials |
OWS_AGENT_TOKEN_EXPIRED | Agent token has expired | Create a new agent token with create_agent_api_key |
MOONPAY_CONFIG_REQUIRED | prepare_onramp called without MoonPay env vars | Set MOONPAY_API_KEY and MOONPAY_SECRET_KEY |
Auth Errors
| Code | Source | When It Happens |
|---|---|---|
UNAUTHORIZED | API | API key is missing or invalid (backend returned 401) |
FORBIDDEN | API | API key is valid but not authorized for this operation (backend returned 403) |
Upstream Errors
| Code | Source | When It Happens |
|---|---|---|
SERVER_ERROR | API | Backend returned 500, 502, or 503 |
TIMEOUT | API | Request exceeded the timeout (default 60s) |
NETWORK | API | DNS or connection failure |
TX_COMPILER_* | API | Transaction compilation failed at the backend |
SIMULATION_FAILED | API | Transaction simulation at the backend failed |
INVALID_BACKEND_RESPONSE | MCP | Backend response did not match the expected schema (MCP client-side guard) |
Limit and Feature Errors
| Code | Source | When It Happens |
|---|---|---|
RATE_LIMITED | API | Backend returned 429 — too many requests |
PLAN_RESTRICTED | API | Backend returned 403 — feature not enabled on your API key |
FEATURE_GATED | MCP | MCP tool classified as not-available for your plan (surfaces PLAN_RESTRICTED to the agent as a not_available category error) |
Consuming errors
The same structured payload reaches the caller through two different wrappers. Pick the sub-section that matches your surface.From an AI agent (MCP)
Every MCP tool response surfaces the structured error verbatim. Thecategory field tells the agent what class of action to take; requiredAction (when present) gives a concrete next step.
A well-behaved agent should:
- Check
category - If
flow— execute therequiredAction, then retry the original request - If
validation— fix the input based on themessage, then retry - If
upstream— retry with exponential backoff (3 attempts, then surface to user) - If
auth— stop and ask the user to fix their credentials - If
limit— wait and retry - If
not_available— inform the user
From the SDK
SDK calls throw anApiError wrapper. The structured payload lives in err.bodySnippet as a JSON string — parse it to reach category, code, and message.
SDK callers only see the API-source categories: validation (from the backend, not Zod), auth, upstream, limit, and not_available. The flow category is MCP-only and will not appear in SDK responses.
url, method, status, attempt) and debug-logging behavior, see SDK Error Handling.
Design Principle
Errors are designed so agents can recover without human intervention whenever possible. Aflow error with a requiredAction gives the agent a concrete next step — it does not need to guess or ask the user for help.
Internal error details (internalMessage) are logged server-side but never included in the response sent to the LLM. The agent sees only what it needs to act on.