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
retry | Do this |
|---|---|
NEVER |
The request is wrong. Retrying it unchanged will fail identically. |
WITH_BACKOFF |
Something upstream did not answer. Back off and retry. |
Codes
| Status | Code | Means, and what to do |
|---|---|---|
| 400 | INVALID_REQUEST |
The body could not be read, or a field was missing or malformed. The detail names the field. |
| 401 | UNAUTHENTICATED |
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. |
| 403 | OUT_OF_SCOPE |
The key is valid and does not reach this network, capability, transport or environment. Issue a key with the scope you need. |
| 403 | CAPABILITY_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. |
| 409 | IDEMPOTENCY_CONFLICT |
The same idempotency key with a materially different request. |
| 422 | NO_SAFE_ROUTE |
Nothing could meet the trust floor, so no answer is returned.
best_available says what you would have got. |
| 422 | UPSTREAM_UNAVAILABLE |
XRPC asked and the chain sources did not answer. Retry with backoff. |
| 422 | UNSUPPORTED |
The operation is not applicable to this network. This is not the same as not implemented. |
| 502 | UPSTREAM_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. Passasset_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 treatUNKNOWNas clear without saying so. Setunknown_accepted_deliberatelyif 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.andmcp.serve only their own paths and return 404 with a plain-text explanation for anything else.