> ## Documentation Index
> Fetch the complete documentation index at: https://docs.atum.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent error reference

> The error codes your settler agent writes to its own logs, what each one means, and what to do about it.

## Who this is for

You run a settlement agent and you are looking at a code in your own logs or traces. This page explains what the agent meant by it.

These codes are internal to the agent you operate. None of them is returned to a payer.

<Warning>
  Two of these strings, `NONCE_TOO_LOW` and `BROADCAST_REJECTED`, are also names in the settlement outcome the agent *reports* to Atum, where both map to the public code `SETTLEMENT_FAILED`. A name coinciding does not make the two the same thing. On this page they always mean the agent-internal condition.
</Warning>

## Where you see these codes

| Surface                                                     | What you get                                                                      |
| ----------------------------------------------------------- | --------------------------------------------------------------------------------- |
| The error message                                           | A signer code, prefixed as `CODE: detail`. Node submission codes are not prefixed |
| The `errorCode` log field on the execution activity's lines | Either taxonomy, whichever the failure carried                                    |
| The `error.code` attribute on the Temporal activity span    | Either taxonomy                                                                   |

## Retryable and terminal

The agent classifies every failure as one of two things, and that decides whether the work is retried or abandoned.

* **Retryable** — a transient condition. The agent retries under its own retry policy. Usually no action from you.
* **Terminal** — provably permanent. The agent stops without retrying and routes the settlement to a terminal outcome. Almost always needs you.

An *unclassified* error is treated as retryable, so an unknown condition is never permanently abandoned on a guess. A permanent failure therefore has to be declared terminal explicitly, and a condition not listed as terminal below is not thereby safe to retry.

The one carve-out is after a broadcast attempt. There an unclassified error is treated as **terminal**, because the transaction may already be in the mempool and retrying would broadcast a second one.

## Signer codes

Raised by the signing layer on any chain. The code is prefixed onto the message, so a log line reads `TURNKEY_RATE_LIMITED: ...`. All of them are terminal except the three Turnkey codes marked retryable below.

| Code                         | Meaning                                                                                                                                | What to do                                                                                     |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| `POLICY_REJECTED`            | Your signing policy declined the transaction. The message carries the reason and the offending field                                   | Read the reason. Either the transaction is genuinely out of policy, or the policy is too tight |
| `POLICY_TX_KIND_MISMATCH`    | The transaction is not an object, or its detected chain kind disagrees with the signer's. A guard against decoder confusion            | Treat as a bug. Do not loosen the guard                                                        |
| `SIGNER_ADDRESS_DRIFT`       | The address the signer is pinned to is not the address the key provider returned, or the transaction's sender is not this signer       | Fix the key provisioning or the pinned address. Never ignore this one                          |
| `SIGNER_NOT_INITIALIZED`     | The signer was used before initialization, the raw private key is invalid, or the wallet has no account in the required address format | Provision an account of the required format. The message names the wallet and the format       |
| `SIGNER_CAPABILITY_MISMATCH` | The configured signer does not implement the method being asked of it, or the chain kind is unknown                                    | Configuration or code fault                                                                    |

### Turnkey signer

Only relevant if you sign through Turnkey.

| Code                         | Class     | Meaning                                                                                                                       | What to do                                                                                                                                                                                                                                                                                     |
| ---------------------------- | --------- | ----------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `TURNKEY_AUTH`               | Terminal  | HTTP 401 or 403. A bad stamp or an unknown public key                                                                         | Rotate or re-register the API keypair                                                                                                                                                                                                                                                          |
| `TURNKEY_NETWORK`            | Retryable | The request never completed, or Turnkey returned a 5xx                                                                        | Nothing during a blip. A 5xx on a state-changing call is surfaced as retryable rather than terminal on purpose, because Turnkey may have committed the activity before failing, so the chain layer decides                                                                                     |
| `TURNKEY_RATE_LIMITED`       | Retryable | HTTP 429 after the local backoff budget was spent. Always safe to retry, because Turnkey rejects before creating the activity | Reduce concurrency, or raise your Turnkey quota                                                                                                                                                                                                                                                |
| `TURNKEY_BAD_RESPONSE`       | Terminal  | A missing result field, a non-JSON body, an unmapped 4xx, or malformed signature parts                                        | Treat a sign-then-recover mismatch as a security event, not a retry                                                                                                                                                                                                                            |
| `TURNKEY_ACTIVITY_FAILED`    | Terminal  | The activity finished in a status other than completed. The status is surfaced verbatim                                       | `ACTIVITY_STATUS_REJECTED`, `ACTIVITY_STATUS_CONSENSUS_NEEDED` and `ACTIVITY_STATUS_PENDING_SIGNERS` are all actionable: a sub-organization policy denied it, or a quorum approval is required. Consensus is recoverable, and the message carries the fingerprint that the approval call takes |
| `TURNKEY_SIGNER_UNAVAILABLE` | Retryable | The activity was still pending when the poll budget ran out                                                                   | Check Turnkey's status, and whether a quorum policy is holding the activity open                                                                                                                                                                                                               |

## Node submission codes

Set when the agent hands a signed transaction to an RPC node, and when the node rejects it. Each chain classifies independently, so the same physical event can land under different codes on different chains.

Unlike the signer codes, these are **not** prefixed onto the message. Read them from the `errorCode` log field or the `error.code` span attribute.

| Code                      | Class     | EVM | Tron | Solana |
| ------------------------- | --------- | --- | ---- | ------ |
| `BROADCAST_REJECTED`      | Retryable | Yes | Yes  | Yes    |
| `BROADCAST_UNCERTAIN`     | Retryable | Yes | Yes  | Yes    |
| `BROADCAST_PHANTOM`       | Retryable | Yes | —    | —      |
| `ALREADY_KNOWN`           | Retryable | Yes | Yes  | Yes    |
| `TX_ALREADY_IN_BLOCK`     | Retryable | Yes | Yes  | Yes    |
| `BLOCKHASH_NOT_FOUND`     | Retryable | —   | —    | Yes    |
| `NONCE_TOO_LOW`           | Retryable | Yes | —    | —      |
| `NONCE_TOO_HIGH`          | Retryable | Yes | —    | —      |
| `REPLACEMENT_UNDERPRICED` | Retryable | Yes | —    | —      |
| `EVM_REVERT`              | Terminal  | Yes | —    | —      |
| `TRON_REVERT`             | Terminal  | —   | Yes  | —      |
| `INSUFFICIENT_FUNDS`      | Terminal  | Yes | —    | —      |
| `TX_TOO_LARGE`            | Terminal  | —   | —    | Yes    |

The three nonce codes and `INSUFFICIENT_FUNDS` need a word each:

* `NONCE_TOO_LOW` — the nonce is already consumed. On a retry this means the earlier transaction mined, and the reconciler resolves it. Nothing to do.
* `NONCE_TOO_HIGH` — an earlier nonce is still pending. Nothing to do.
* `REPLACEMENT_UNDERPRICED` — a replacement was priced below the node's bump threshold. The agent re-bumps at the same nonce. Nothing to do.
* `INSUFFICIENT_FUNDS` — terminal. Top up the signing address's native gas balance on that chain.

### Rejected and uncertain are not the same thing

This is the distinction worth internalizing, because it decides whether the agent waits or retries.

**Rejected** means the transaction is definitively not in flight. An RPC gateway returning 503, "no healthy upstream", or 502 means the request never reached a chain node at all. The agent releases the fulfillment lock and the nonce reservation and fails fast, and Temporal retries the activity.

**Uncertain** means the agent does not know. A 504, or a timeout after the request reached upstream, could mean the transaction landed. The agent **keeps** the fulfillment lock and the nonce reservation and hands off to the reconciler, which watches the chain to find out.

**Phantom** is a stricter check on top of a *successful* broadcast, and it exists on EVM only. Transaction hashes are computed client-side, so a 200 OK does not prove the node accepted or propagated anything. Some RPC providers return success and silently drop the transaction. After broadcasting, the agent polls the node for the transaction it just sent. If the node does not return it within the verification window, that is a phantom.

### What each bucket does

| Codes                                                         | Fulfillment lock | Nonce reservation | Outcome                                       |
| ------------------------------------------------------------- | ---------------- | ----------------- | --------------------------------------------- |
| `BROADCAST_UNCERTAIN`, `ALREADY_KNOWN`, `TX_ALREADY_IN_BLOCK` | Retained         | Retained          | Handed to the reconciler                      |
| `BROADCAST_REJECTED`, `BROADCAST_PHANTOM`                     | Released         | Released          | Activity retried                              |
| `NONCE_TOO_HIGH`, first-attempt `NONCE_TOO_LOW`               | Released         | Force-released    | Activity retried                              |
| `REPLACEMENT_UNDERPRICED`                                     | Retained         | Retained          | Activity retried, re-bumped at the same nonce |

Releasing the reservation frees the ledger row, not the nonce value. A retry reads the nonce off the prior attempt and reuses it, and on EVM, where the signed bytes were persisted, re-broadcasts those same bytes rather than signing something new. One hash per nonce is what makes a single receipt conclusive.

### Sizing the verification window

You do not set the phantom verification window directly. It is derived as 60% of `attemptTimeoutMs`, the per-chain plugin setting in your chain configuration, which defaults to 60000 ms and gives a 36000 ms window.

<Warning>
  Size `attemptTimeoutMs` from your RPC provider's read-your-own-write latency, not from block time. A provider that load-balances reads across nodes can take seconds to serve back a transaction it just accepted, on any chain, however fast that chain produces blocks. A window shorter than that latency turns healthy broadcasts into phantoms, and the retry re-broadcasts at the same nonce. 6000 ms is a working floor for `attemptTimeoutMs` on a public RPC endpoint. Raise it for a provider known to be slow.
</Warning>

### Chain differences to know about

Two events are classified differently depending on the chain, and both matter operationally.

* A node that acknowledges a broadcast without actually holding the transaction is `BROADCAST_PHANTOM` on EVM, `BROADCAST_UNCERTAIN` on Tron, and is not detected on Solana.
* A contract revert seen at submit time is **terminal** on EVM and Tron, and **retryable** on Solana.

## Next steps

<CardGroup cols={2}>
  <Card title="Troubleshooting" icon="wrench" href="/get-started/support/troubleshooting">
    The payer-facing errors, for when the problem is a payment rather than your agent
  </Card>

  <Card title="Configuration" icon="sliders" href="/settle-payments/configuration/overview">
    Profile and chain configuration for the agent
  </Card>
</CardGroup>
