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

# Errors and Limits

> The error envelope, error codes, and rate limits.

## The envelope

Every failure shares one shape:

```json theme={null}
{
  "success": false,
  "error": {
    "code": "ORDER_REJECTED",
    "message": "Human-readable description",
    "reason": "NOT_REGISTERED"
  }
}
```

Branch on `error.code`. Treat `error.message` as display text, because it is not stable enough to parse.

## Codes

| Code                  | Status | Meaning and what to do                                                                     |
| --------------------- | ------ | ------------------------------------------------------------------------------------------ |
| `UNAUTHORIZED`        | 401    | Bad key, bad signature, or a timestamp outside the receive window. Check clock drift first |
| `FORBIDDEN`           | 403    | The key lacks the `trade` scope                                                            |
| `ORDER_REJECTED`      | 400    | Validation failed. Carries a `reason`, listed below                                        |
| `ORDER_NOT_FOUND`     | 404    | Unknown order hash                                                                         |
| `ATTESTATION_INVALID` | 401    | The `NoiseAuth` signature or its timestamp did not verify                                  |
| `NONCE_CONFLICT`      | 409    | Rotate at the nonce the error names                                                        |
| `KEY_NOT_FOUND`       | 404    | Unknown API key on revoke                                                                  |
| `ASSET_NOT_FOUND`     | 404    | Unknown asset id                                                                           |
| `RATE_LIMIT_EXCEEDED` | 429    | Back off. Carries `retryAfterSeconds`                                                      |
| `TRADING_DISABLED`    | 503    | Trading is paused. Submits only; **cancels still work**                                    |

### `ORDER_REJECTED` reasons

| Reason                | Meaning                                                               |
| --------------------- | --------------------------------------------------------------------- |
| `INVALID_FIELDS`      | A field failed validation                                             |
| `INVALID_SIGNATURE`   | The recovered signer or order hash did not match the submitted values |
| `INVALID_FLAGS`       | `postOnly` and `reduceOnly` were equal. Exactly one must be true      |
| `ASSET_NOT_TRADEABLE` | The market is not accepting orders                                    |
| `PRECISION`           | More precision than the 0.000001 floor allows                         |
| `TICK_SIZE`           | Price is not a multiple of the market's `tickSize`                    |
| `LOT_SIZE`            | Size is not a multiple of the market's `lotSize`                      |
| `MAX_LEVERAGE`        | Collateral too low for the size at this market's limit                |
| `EXPIRY`              | Expiry is in the past or more than 2 years out                        |
| `NOT_CANCELLABLE`     | The order is already filled, expired, or cancelled                    |
| `NOT_REGISTERED`      | The wallet has no exchange account yet                                |

<Info>
  These are rejections at submission. An order the engine **accepts** can still be rejected later,
  which surfaces as `rejectCode` on the order itself rather than as an API error. See
  [Accepted is not filled](/trader-api/orders#accepted-is-not-filled).
</Info>

## Rate limits

Budgets are **per key** for submits, cancels, mass-cancels, and reads, with additional IP tiers on the public routes. Moving traffic to the WebSocket does not raise them.

Responses from rate-limited routes carry the current state:

| Header                  | Meaning                        |
| ----------------------- | ------------------------------ |
| `x-ratelimit-limit`     | Requests allowed in the window |
| `x-ratelimit-remaining` | Requests left                  |
| `x-ratelimit-reset`     | When the window resets         |

Not every response carries them. `GET /health` and requests that fail authentication are answered before the limiter runs, so all three headers are absent; treat them as present-when-metered rather than guaranteed.

A `429` additionally carries `retryAfterSeconds`, `limit`, `remaining`, and `resetAt` in the error body. Respect `retryAfterSeconds` rather than retrying on a fixed interval.

Mass-cancel fan-out never consumes the per-order cancel budget, so withdrawing all resting orders during a halt is not rate-limited.

<Warning>
  Read the live limits from `GET /status`, which publishes them as a machine-readable table, rather
  than hardcoding them. The published values are provisional ahead of general availability and will
  change.
</Warning>

## Retrying safely

Most write routes are safe to retry, by design:

* **Order submission** is idempotent by order hash. Resubmitting the identical signed order returns the original with `idempotent: true` rather than doubling the position.
* **Registration** is idempotent.
* **Credential issuance** is derive-or-create at a given nonce, so a retry returns the same credentials with `existing: true`.

Retry on `429` and `5xx`. Do not retry a `400` or a `401` without changing something: a rejected signature will be rejected identically every time.
