Skip to main content
Every error response uses the envelope described in Errors. Branch on error.code. The message is written for people and may be reworded. This page lists every code in the API’s error registry. If a close fails halfway, read Recovery first: it explains what state the account is in.

Reading the Retry column

Three rules that apply to every row:
  • Every 503 and every 429 carries a Retry-After header. On a 503 it is a fixed default of 30 seconds, not a measured recovery time. A 503 does not always mean waiting helps: registry_expired and the *_not_configured codes are marked No because they need the operator to act.
  • The status column is the HTTP status the code is returned with. request_failed is any other 4xx status, and defi_positions_unavailable is raised as a plan blocker rather than a fixed status.
  • The SDK retries only the calls and statuses it documents, and never retries submit.

What to show the user

Show the plain-language message, never the code, the status or a stack trace. When something goes wrong that the user cannot fix, show the error.requestId as a reference they can quote when they ask for help. A message from a blocker or a 422 already names what to do, so display it as written.

Request and authentication

These mean the request itself is wrong or not allowed. Treat them as a fault in the calling code: fix the request and do not resend it unchanged. A user has nothing to act on, so show a short “this request could not be completed” message with the reference id. unauthorized means the API key is missing or invalid, and forbidden means the key may not do this.

Availability and rate limits

These are transient. Retry with backoff, honoring Retry-After. While retrying, show “The service is busy, trying again”. If it keeps failing, show the message and the reference id.

Reading accounts and routes

A failed read is not an answer. destination_read_failed is never reported as a missing destination, and account_read_failed, allowances_read_failed and path_lookup_failed are safe to retry. account_not_found is a real answer: the account does not exist on that network, or it has already been merged. account_too_large means the account has more entries than one request can read.

Planning and building a close

These come from close/plan and close/transactions. The message names the problem and usually what resolves it, so show it as written. Several carry details: needs_decisions lists the unanswered decisions in details.missing, a missing transfer destination or conversion floor names its details.decisionId, and merge_destination_unusable lists details.problems. quote_drifted means a conversion route changed between planning and building: plan again and let the user choose again, or pick a transfer, which needs no route. source_sequence_too_far cannot be fixed by the user or the API: the account can be closed only once the network’s ledger count catches up.

DeFi position exits

A position that cannot be closed safely is reported, never skipped. Show the message, which says what to do in the protocol itself (repay a loan, claim rewards, add a trustline, wait out a cooldown). After the user has done that, analyze the account again and plan again. defi_positions_stale means the detected positions are out of date, so plan again. defi_positions_unavailable appears as a plan blocker when detection could not confirm the account’s positions: analyze again.

Soroban token balances

These refuse a conversion or transfer of a Soroban token that cannot be done safely. Show the message. Where a conversion is refused, offer a transfer to an account the user names. soroban_token_unreadable is a failed read and is safe to retry.

Submitting a transaction

submit waits up to 90 seconds for confirmation. submit_rejected carries the network’s own reason in details.resultCode, for example tx_too_late for an expired transaction or tx_bad_seq for a stale sequence number. Build and sign a fresh transaction rather than resending the old one. confirmation_timeout and submit_failed do not tell you whether the transaction landed. Look the hash up on an explorer before doing anything else. Resubmitting the identical signed transaction is safe, because the API reports an already confirmed transaction as a success. Never rebuild and sign a second transaction while the first may still confirm. See Recovery.

Exchange relay, sponsored fees and the registry

A refusal here happens before anything is submitted, so nothing has changed on the ledger. transaction_structure_not_allowed means the transaction is not the exact shape the relay or the fee sponsor will sign, and sending it again will not change that. registry_expired and the *_not_configured codes are about the server, not the request: show the message, and offer a destination that is not an exchange where one exists.

Allowance revocation

These come from the allowance endpoints. revoke_needs_restore means ledger entries have to be restored before the revocation can be built. revoke_build_failed is safe to retry.

API keys, operator routes and stats

These belong to key management, the operator routes and the public stats counter. invalid_challenge means the signed sign-in message is invalid or has expired: request a new one. tx_not_verified means the transaction is not a confirmed account merge on that network. Check the hash and the network before sending it again.

Keeping this page current

The Status and Meaning columns repeat the generated registry on the introduction page. A check in the repository fails when a code is added to the API without a row here, when a row names an unknown code, or when a status or meaning differs from the generated table.