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

# Handling errors

> Read an error, decide whether to retry, and fix the request.

Every error has the same shape. It says what was wrong, gives one way to fix it, and says whether retrying can help.

```json theme={"system"}
{
  "error": {
    "type": "permission",
    "code": "key_daily_limit_exceeded",
    "message": "This key may place $100.00 of orders per 24 hours. $92.40 is used, so $7.60 remains, which is less than the $10.00 minimum order.",
    "param": "value",
    "hint": "$40.00 frees up at 14:05 UTC, when an earlier order leaves the 24-hour window. The account owner can raise the limit on the account page.",
    "details": {
      "limit": "100.00",
      "used": "92.40",
      "remaining": "7.60",
      "next_release": { "at": "2026-09-28T14:05:11.000Z", "value": "40.00" }
    },
    "errors": [],
    "retryable": true,
    "retry_after": "2026-09-28T14:05:11.000Z",
    "doc_url": "https://docs.tradingapi.dev/api-reference/errors#key_daily_limit_exceeded"
  }
}
```

| Field | Use it for |
| - | - |
| `type` | The kind of error. It sets the HTTP status. |
| `code` | What went wrong, as a stable identifier. Branch on this. |
| `message` | What went wrong, in a sentence, with the values involved. Show it or log it. |
| `param` | The request field at fault, or `null`. |
| `hint` | One concrete way to fix the request. |
| `details` | The numbers from the message, as fields, so your code doesn't have to parse text. |
| `errors` | Every field error, when several fields are wrong at once. |
| `retryable` | Whether the same request can succeed later, unchanged. |
| `retry_after` | When it can succeed, if we know. |
| `doc_url` | This code's entry in the [error reference](/api-reference/errors). |

## Nothing happened

An error response means nothing was recorded, so you can always fix the request and send it again. There is one exception. After `503` or `500`, the order may have been recorded just before the failure, so retry with the same `client_order_id` ([Retries and idempotency](/guides/retries) explains why that is safe).

Problems that happen after an order is recorded, such as the exchange refusing it, are not errors. You get the order back with `status: "rejected"` and a `status_reason`. See [Orders](/concepts/orders#why-an-order-was-canceled-or-rejected).

## Deciding what to do

```python theme={"system"}
def handle(error: dict) -> str:
    if error["retryable"]:
        return "retry"          # Same request; after retry_after if it is set.
    if error["type"] in ("invalid_request", "unprocessable"):
        return "fix"            # Change the request using hint and details.
    if error["type"] == "permission":
        return "ask the owner"  # The key's limits; only the account page can change them.
    return "stop"
```

| Type | Status | Meaning | Retry unchanged? |
| - | - | - | - |
| `invalid_request` | 400 | The request is malformed or breaks a rule. | No |
| `authentication` | 401 | The API key is missing, wrong or revoked. | No |
| `permission` | 403 | The key's limits refuse the order. | Only the daily limit, after `retry_after` |
| `not_found` | 404 | The market, order or position does not exist. | No |
| `conflict` | 409 | The `client_order_id` is taken, or the account can't trade. | No |
| `unprocessable` | 422 | The request is valid, but your balance or position doesn't allow it now. | No |
| `unavailable` | 503 | A service we depend on failed. | Yes |
| `internal` | 500 | Something failed on our side. | Yes |

## Several problems at once

When more than one field is wrong, you get every problem in one response, so you can fix them all at once:

```json theme={"system"}
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_fields",
    "message": "3 fields are invalid.",
    "param": null,
    "hint": "Fix each field listed in errors.",
    "details": {},
    "errors": [
      { "type": "invalid_request", "code": "invalid_value", "param": "side", "message": "side is \"long\". Orders use \"buy\" or \"sell\"; \"long\" describes a position.", "hint": "To open a long, send \"side\": \"buy\".", "details": {}, "errors": [], "retryable": false, "doc_url": "https://docs.tradingapi.dev/api-reference/errors#invalid_value" },
      { "type": "invalid_request", "code": "unknown_field", "param": "amount", "message": "amount is not a field of this request.", "hint": "Did you mean value? It is the order's size in USD.", "details": {}, "errors": [], "retryable": false, "doc_url": "https://docs.tradingapi.dev/api-reference/errors#unknown_field" },
      { "type": "invalid_request", "code": "missing_field", "param": "value", "message": "value is required.", "hint": "Send how much to buy or sell in USD, for example \"value\": \"25.00\".", "details": {}, "errors": [], "retryable": false, "doc_url": "https://docs.tradingapi.dev/api-reference/errors#missing_field" }
    ],
    "retryable": false,
    "doc_url": "https://docs.tradingapi.dev/api-reference/errors#invalid_fields"
  }
}
```

A preview (`POST /v1/orders/preview`) returns the same list without the error status, and also checks your key's limits and balance.

The [error reference](/api-reference/errors) lists every code.
