Skip to main content
Every error from WalletSuite includes a 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

{
  "category": "validation",
  "code": "INVALID_ADDRESS",
  "message": "Address does not match expected format for ethereum"
}
For flow errors, a requiredAction is always included:
{
  "category": "flow",
  "code": "OWS_WALLET_NOT_FOUND",
  "message": "Wallet 'my-vault' does not exist in the OWS vault",
  "requiredAction": "Create a wallet first using create_wallet with walletName 'my-vault'"
}

Error Categories

CategoryWhere it appearsMeaningWhat the caller should do
validationSDK + MCPBad input — address format, missing field, invalid amountFix the input and retry
upstreamSDK + MCPBackend API or RPC failure, possibly transientRetry with exponential backoff
flowMCP onlyPrerequisite missing — OWS wallet not found, signing not configuredExecute the requiredAction first, then retry
authSDK + MCPAPI key invalid, missing, or unauthorizedStop — tell the user to configure credentials
limitSDK + MCPRate or quota exceededBack off, retry after the rate limit window
not_availableSDK + MCPFeature not enabled for this API keyInform the user the feature is not on their plan

Common Error Codes

Every error carries a code. 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

CodeSourceWhen It Happens
INVALID_ADDRESSMCPAddress fails Zod format check for the specified chain (e.g., not 0x-prefixed for EVM) — raised before the API call
INVALID_AMOUNTMCPHuman-readable amount is not a positive decimal string
INVALID_AMOUNT_WEIMCPWei amount is not a positive integer string
MISSING_TOKEN_CONTRACTMCPToken transfer attempted with a symbol but no contract address — use resolve_asset first
INVALID_PARAMSMCPZod schema validation failed on tool input
BAD_REQUESTAPIBackend returned 400 — check the request parameters
NOT_FOUNDAPIBackend 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.
CodeWhen It HappensRequired Action
OWS_WALLET_NOT_FOUNDNamed wallet does not exist in the vaultCreate the wallet with create_wallet
OWS_ACCOUNT_NOT_FOUNDWallet exists but has no account for the requested chainCheck supported chains or create a new wallet
OWS_REQUIREDSign/broadcast tool called without OWS enabledSet OWS_ENABLED=true and configure OWS
OWS_POLICY_DENIEDPolicy rejected the signing requestModify the policy or use a different wallet/chain
OWS_RPC_URL_REQUIREDsend_transaction called without the chain RPC URLSet OWS_ETHEREUM_RPC_URL or OWS_TRON_RPC_URL
OWS_CREDENTIAL_INVALIDPassphrase or agent token cannot unlock the vaultCheck credentials
OWS_AGENT_TOKEN_EXPIREDAgent token has expiredCreate a new agent token with create_agent_api_key
MOONPAY_CONFIG_REQUIREDprepare_onramp called without MoonPay env varsSet MOONPAY_API_KEY and MOONPAY_SECRET_KEY

Auth Errors

CodeSourceWhen It Happens
UNAUTHORIZEDAPIAPI key is missing or invalid (backend returned 401)
FORBIDDENAPIAPI key is valid but not authorized for this operation (backend returned 403)

Upstream Errors

CodeSourceWhen It Happens
SERVER_ERRORAPIBackend returned 500, 502, or 503
TIMEOUTAPIRequest exceeded the timeout (default 60s)
NETWORKAPIDNS or connection failure
TX_COMPILER_*APITransaction compilation failed at the backend
SIMULATION_FAILEDAPITransaction simulation at the backend failed
INVALID_BACKEND_RESPONSEMCPBackend response did not match the expected schema (MCP client-side guard)

Limit and Feature Errors

CodeSourceWhen It Happens
RATE_LIMITEDAPIBackend returned 429 — too many requests
PLAN_RESTRICTEDAPIBackend returned 403 — feature not enabled on your API key
FEATURE_GATEDMCPMCP 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. The category field tells the agent what class of action to take; requiredAction (when present) gives a concrete next step. A well-behaved agent should:
  1. Check category
  2. If flow — execute the requiredAction, then retry the original request
  3. If validation — fix the input based on the message, then retry
  4. If upstream — retry with exponential backoff (3 attempts, then surface to user)
  5. If auth — stop and ask the user to fix their credentials
  6. If limit — wait and retry
  7. If not_available — inform the user

From the SDK

SDK calls throw an ApiError 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.
import { WalletSuiteSDK, ApiError } from "@walletsuite/wallet-sdk";

try {
  const balance = await sdk.api.getNativeBalance(address, "ethereum");
} catch (err) {
  if (err instanceof ApiError && err.bodySnippet) {
    try {
      const payload = JSON.parse(err.bodySnippet);
      switch (payload.category) {
        case "validation":    /* fix input, retry */         break;
        case "upstream":      /* retry with backoff */       break;
        case "auth":          /* check credentials */        break;
        case "limit":         /* wait and retry */           break;
        case "not_available": /* inform the user */          break;
      }
    } catch {
      // non-JSON body — transport-level failure (timeout, DNS, etc.)
    }
  }
}
For SDK-specific wrapper fields (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. A flow 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.