Errors and refusals

A refusal is an answer. Every one names the field or the reason, and says whether retrying could ever help.

{
  "code":       "INVALID_REQUEST",
  "message":    "the request was not one this surface could read",
  "retry":      "NEVER",
  "request_id": "req_000000000011",
  "detail": {
    "message": "`balance.get` needs `asset`. It takes address, asset",
    "refusal": { "field": "asset", "refusal": "MISSING_FIELD" }
  }
}

Always log request_id. It is the one value that lets a specific call be traced.

Retry semantics

retryDo this
NEVER The request is wrong. Retrying it unchanged will fail identically.
WITH_BACKOFF Something upstream did not answer. Back off and retry.

Codes

StatusCodeMeans, and what to do
400INVALID_REQUEST The body could not be read, or a field was missing or malformed. The detail names the field.
401UNAUTHENTICATED No usable key. On the MCP endpoint this is returned before the body is parsed at all, so an unauthenticated caller learns nothing about their JSON.
403OUT_OF_SCOPE The key is valid and does not reach this network, capability, transport or environment. Issue a key with the scope you need.
403CAPABILITY_NOT_AVAILABLE Not commercially available on this deployment. No key reaches it; another key will not help.
404 No such route on this host, or no such object in your project. Another project's object is not found rather than forbidden, so ids do not leak.
409IDEMPOTENCY_CONFLICT The same idempotency key with a materially different request.
422NO_SAFE_ROUTE Nothing could meet the trust floor, so no answer is returned. best_available says what you would have got.
422UPSTREAM_UNAVAILABLE XRPC asked and the chain sources did not answer. Retry with backoff.
422UNSUPPORTED The operation is not applicable to this network. This is not the same as not implemented.
502UPSTREAM_UNAVAILABLE An internal plane did not answer. Nothing was partially applied.

Refusals that are working as intended

  • DECIMALS_UNKNOWN — an amount whose scale XRPC has not established is refused rather than reinterpreted. Pass asset_decimals.
  • EVERY_ROUTE_REFUSED — from Send, carrying the node's own message. The chain rejected your bytes; XRPC did not alter them.
  • SOURCE_REFUSED — a configured source could not be asked who it is, so nothing was established. The endpoint is never echoed back, because it may carry a credential.
  • POLICY_REFUSED — a compliance policy that would treat UNKNOWN as clear without saying so. Set unknown_accepted_deliberately if that is genuinely your policy.

Edge behaviour

The edge rejects the raw Python-urllib user-agent with a Cloudflare 1010 page, before the request reaches XRPC. It is not an XRPC error and carries no request_id. requests, httpx, node-fetch, Go's HTTP client, axios and curl all pass. If you are calling from Python, use requests or httpx, or set an explicit User-Agent.
  • /admin*, /metrics* and /debug* return 404 on every public host.
  • pay. and mcp. serve only their own paths and return 404 with a plain-text explanation for anything else.