# Errors and troubleshooting

> What each SDK error means, and fixes for the problems people meet first.

Status: In development. Not released yet; names and formats may change. Web page: https://retrade.app/docs/errors

## Errors and answers

An answer is never an error. ALLOW, CUT, BLOCK and reTrade not answering all come back as a result. Errors are for your code to fix, and every one is a `ReTradeError`. The names are the same in both SDKs.

The SDK’s errors:

| Error | When | What to do |
|---|---|---|
| `InvalidInput` | A value the SDK can’t send: a float price, a limit order without a limit price, a stop price of 0, a time without a timezone. | Fix the order or the adapter’s data. |
| `ConfigError` | A malformed key id, root key or server address, or an adapter whose settings differ from the account’s at reTrade. | Fix the setup. |
| `RequestRefused` | reTrade refused a request as malformed or unauthorised: a 4xx other than 429. It has `status` and `detail`. | Don’t retry: fix the request or the key. |
| `KeyFileError` | The key file can’t be created or used. | See below. |
| `VerificationFailed` | Something claiming to be from reTrade failed a check, outside `place`: the key list, the status or a log record. | Check the root key and the address. The SDK never acts on it. |
| `Unreachable` | No usable answer in time, from a call other than `place`, which blocks the order instead. | Retry later. |
| `BrokerRejected` | Raised by your adapter’s `submit` when the broker definitely refused the order. | Nothing: the SDK reports it as rejected. |

## Setup problems

### KeyFileError: the key is accessible by its group or others

The SDK refuses a key file other users can read. Run `chmod 600 executor.pem`.

### KeyFileError: the key already exists

`retrade keygen` never overwrites a key. Choose another path, or keep using the key you have.

### ConfigError: not an executor key id

A bot key id is `exk_`, the mode (`enforce`, `shadow` or `test`), `_`, then 26 characters. Copy it exactly as your admin sent it.

### ConfigError: root_key is not a base64url Ed25519 public key

The root key is 43 characters of base64url. Check for a missing character or stray quotes.

### VerificationFailed: bad signature on a retrade-keys document

The key list at your server address wasn’t signed by the root key you pinned. Check `RETRADE_ROOT_KEY`, and that `RETRADE_BASE_URL`, if it’s set, points at the right server.

### ConfigError: plain http is allowed only for a loopback address

Use `https`, or `http` only for a server on your own machine (`127.0.0.1`, `localhost` or `::1`).

### ConfigError: the adapter’s settings differ from the account’s

Your adapter’s `g_seconds` and `converts_cash` (`gSeconds` and `convertsCash`) must equal the account’s settings at reTrade. Ask your admin for them.

### ConfigError: the adapter returned no quote

When `instrument` is given, your adapter’s `snapshot` function must return a quote for it.

### InvalidInput: a price must be a Decimal or a decimal string

Money is exact. In Python use `Decimal("187.25")`, or `Decimal(str(x))` for a float your broker gives you; in TypeScript use `"187.25"` or `String(x)`, never `187.25`.

### Node prints an ExperimentalWarning for SQLite

The TypeScript SDK keeps its claim kit with Node’s built-in `node:sqlite`. On Node 22, Node warns about it; the warning changes nothing.

## Problems with answers

### Every order comes back unreachable

The SDK couldn’t get an answer within 2.5 seconds. From the machine your bot runs on, check that `curl https://api.retrade.app/healthz` answers `{"ok":true}`, that `RETRADE_BASE_URL` isn’t set to an old address, and that outgoing HTTPS is allowed.

### Answers come back unverified

Most often it’s your clock: the SDK refuses an answer made more than 60 seconds from your clock, so turn on time sync (NTP). Otherwise the answer failed a signature or order check, and the SDK’s log says which.

### BLOCK with QUOTE-STALE, STATE-STALE or STATE-MISSING

Your adapter sent an old quote or old account data. Read both from the broker each time `snapshot` is called, and set `as_of` to when you read them. A price older than 30 seconds is a BLOCK.

### BLOCK with STATE-INCOMPLETE on a market buy

For a market buy of a stock the account doesn’t hold, include a position of 0 shares with its current mark.

### BLOCK with STATE-JUMP

The account’s value jumped since its last accepted data. Send the deposits, withdrawals, dividends, fees, transfers and splits since `adjustments_since` as adjustments, or have an admin confirm the data.

### BLOCK with ACCOUNT-UNKNOWN

The account ref isn’t in your tenant’s register. Check it with your admin.

### A result with reason expired

The approval ran out before the broker call: 30 seconds by default, counted from when the SDK sent the request. Nothing was placed. Ask again.

### A placement of unknown

Your adapter’s `submit` raised something other than `BrokerRejected`, and `find` couldn’t see the order. The broker may still have it. Don’t send it again: reconcile from the broker’s own order list. The decision keeps counting at reTrade until the account data shows the order or its absence.

### send_snapshot raises RequestRefused (HTTP 404)

Snapshots sent with no order aren’t built on the hosted service yet. `keep_fresh` (`keepFresh`) only logs the 404.

## Check the service

```shell
curl -fsS https://api.retrade.app/healthz
```

It answers `{"ok":true}` when the hosted service is up.

> Still stuck? Your admin can see your tenant’s settings. For a pilot, [ask on the home page](https://retrade.app/#pilot).
