# Troubleshooting

When a request fails, we return an error with a stable code and a readable
message. We recommend that your agent branch on the error code, since the code
is the stable identifier, and not match on the message text.

If an action fails with a policy or authorization error, don't retry it
unchanged. Instead, read the reasons, then either change the request or ask a
person who can change the [policy](https://docs.catena.com/policies.md) or approve the action (an admin).

## Error format

Most API errors return the following body:

```json
{ "error": "A readable message.", "code": "stable_code", "requestId": "..." }
```

There are three fields in this error body:

| Field       | Description                                                                 |
| ----------- | --------------------------------------------------------------------------- |
| `error`     | A message in plain English that is safe to show a person.                   |
| `code`      | A stable identifier. This is `null` when the route doesn't set one.         |
| `requestId` | Identifies the request. Include it when you contact support about an error. |

Errors from agent authentication are shaped differently. They put the stable
code in `error` and the readable text in `message`:
`{ "error": "stable_code", "message": "A readable message." }`. Your agent
should read both fields.

The CLI prints the readable message on stderr (standard error). The [SDK](https://docs.catena.com/sdk.md)
raises an `ApiError` with `code`, `status`, `fields`, and `details`.

## Linking

Below are the problems you may see while linking an agent, along with the cause
of each.

| Symptom                                            | Cause                                                                           | What to do                                                                                         |
| -------------------------------------------------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------- |
| The link expired                                   | 15 minutes passed before the link was approved.                                 | Run the same `catena link` command, which will print a new link.                                   |
| The person declined                                | The person denied the request or cancelled their approval.                      | Stop. Only start again if they ask you to, after running `catena unlink --profile <name> --force`. |
| `Already linked` when you wanted a new agent       | The directory is already bound to a profile.                                    | Pass `--profile <new name>`.                                                                       |
| `created_out_of_window`                            | The machine's clock is wrong.                                                   | Fix the clock. Linking again won't help.                                                           |
| `client_upgrade_required`                          | Catena no longer accepts this CLI version.                                      | Run `npm i -g @catena/cli`, then try again.                                                        |
| The agent has as many linked clients as allowed    | The agent reached the signing provider's limit on linked clients.               | Unlink one of the agent's machines, or revoke one of its secret keys.                              |
| A keychain write is refused                        | A sandboxed tool (e.g., Codex's default sandbox) blocks writes to the keychain. | Approve the sandbox's escalation, or use a [secret key](https://docs.catena.com/connect/secret-keys.md).                     |
| `Linux Secret Service credential operation failed` | A CLI older than 0.17 is running on a Linux host with no keyring.               | Upgrade the CLI. Current versions store the key in a file instead.                                 |

## Signing and authentication

| Code                                                                         | Cause                                                                          | What to do                                                                                                        |
| ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| Catena rejected this machine's signing key                                   | The machine was unlinked, or its key was revoked.                              | Run `catena link` again.                                                                                          |
| The error names `CATENA_SECRET_KEY`                                          | The secret key was revoked or is wrong.                                        | Create a new key in the console and set the variable again. Don't run `link`.                                     |
| `missing_auth`, `missing_signature_headers`, `unsupported_signature_profile` | A proxy between the agent and Catena changed or removed the signature headers. | Make sure the proxy keeps all four `Catena-*` headers, the URL, and the body. Note that a new key won't fix this. |
| `signature_auth_disabled`                                                    | The API you're calling doesn't accept signed requests.                         | Check the API URL.                                                                                                |
| "Local signer public key does not match"                                     | Catena holds a different wallet key for this link.                             | Run `catena unlink --profile <name>`, then `catena link <agent-id> --profile <name>`, and approve the new link.   |

## Payments

Below are the errors your agent may receive when it sends a payment. Where an
error carries an HTTP status, it is shown in parentheses.

| Code                                     | Cause                                                                                                               | What to do                                                                                                                                                                                                                                       |
| ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `rail_method_mismatch`                   | The method doesn't match the rail.                                                                                  | Use `ach` or `wire` for a bank rail, and `on-chain` for a wallet rail. See [Send wires and ACH](https://docs.catena.com/wires-and-ach.md#send-a-payment).                                                                                                                  |
| `policy_send_account_required` (400)     | The policy allows several source accounts, and the request didn't name one.                                         | Pass `--account`.                                                                                                                                                                                                                                |
| `policy_send_account_unavailable` (403)  | The policy allows no source account for this send.                                                                  | Ask an admin to check the policy.                                                                                                                                                                                                                |
| `movement_wallet_approval_open` (409)    | Another payment from the same wallet is being approved or signed. Nothing moved.                                    | Wait until `details.heldUntil`, or a few seconds when it's null, then send again. Use a new idempotency key when `details.intentCancelled` is true, and the same key when it's false. If this lasts more than a few minutes, stop and report it. |
| `movement_authorization_in_progress`     | The first send of this payment is still being authorized.                                                           | Wait, then send the same request again with the same key.                                                                                                                                                                                        |
| `wallet_send_intent_not_executing` (409) | The payment was already prepared.                                                                                   | Run `catena intents get <id>`. Don't use a new key.                                                                                                                                                                                              |
| `wallet_send_action_not_yet_enabled`     | Payments on that network aren't available yet.                                                                      | Let the user know. Don't retry.                                                                                                                                                                                                                  |
| `onchain_network_closed` (409)           | Catena has made the network temporarily unavailable. Nothing moved, and payments already in progress will complete. | Don't retry on that network. Use one of the networks in `details.alternatives`, or let the user know.                                                                                                                                            |
| `rate_limited` (429)                     | Your organization sent too many bank payments in a minute.                                                          | Wait for `Retry-After`, then send again.                                                                                                                                                                                                         |
| `intent_not_cancellable` (409)           | The intent has already started executing.                                                                           | Follow it with `intents get`.                                                                                                                                                                                                                    |
| 409 on an idempotency key                | The same key was reused with different inputs.                                                                      | Use a new key for a new operation.                                                                                                                                                                                                               |

> [!NOTE] **Retrying with the same key**
>
> Several of these errors ask your agent to send the same request again with the
> same idempotency key. The same key with the same inputs will return the
> original intent, and no money will move a second time. The exception is
> `movement_wallet_approval_open` with `details.intentCancelled: true`: we
> cancelled that intent, and its key would only return it, so your agent should
> send again with a new key. If your agent is starting a new operation, it
> should use a new key, since a key reused with different inputs will fail with
> a 409. See [Retry safely](https://docs.catena.com/intents.md#retry-safely) for the full rules.

## Payment reasons

The following codes appear in an [intent's](https://docs.catena.com/intents.md) `reasons` field. They are
not returned as errors.

| Reason                                                       | Meaning                                                                                                                                   |
| ------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `agent_signer_not_registered`, `operator_signature_required` | The agent has no wallet signing key, so the payment will wait for an admin. Once signing setup is done, relink the agent with `--relink`. |

## Report a problem

If you run into an unclear message, a missing command, or an operation the CLI
cannot express, we would like to hear about it. You can send feedback to the
Catena team from the CLI:

```sh
catena feedback --help
catena feedback "What I was trying to do, what happened, and the evidence."
```

## Related

- [Intents and retries](https://docs.catena.com/intents.md): Learn how an intent moves through its statuses and resolutions, which fields explain its result, and how to retry safely with idempotency keys.
- [Set policies](https://docs.catena.com/policies.md): Decide what each agent can do with its policy, from the accounts it can read and the counterparties it can pay to its spending rules and temporary overrides.
- [CLI reference](https://docs.catena.com/cli.md): The public commands in @catena/cli 0.19.0, generated from the CLI's help text.
