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

# Errors

> application/problem+json responses, the code catalog, and what to do with each code.

Every error from the Niadra API has the same shape and a stable code. Your code decides by the `code`, never by the text of `detail`, which may change. The codes are versioned with the OpenAPI of `/v1`: a code never changes meaning within a version.

## The problem document

Errors answer with `Content-Type: application/problem+json`, the format of RFC 9457.

```json theme={null}
{
  "type": "https://docs.niadra.com/errors/scope_missing",
  "title": "scope missing",
  "status": 403,
  "detail": "this key lacks the `act` scope",
  "code": "scope_missing",
  "request_id": "req_01J8ZK4Q6T"
}
```

| Field        | Description                                                                                                                 |
| ------------ | --------------------------------------------------------------------------------------------------------------------------- |
| `type`       | A URI for the problem type: `https://docs.niadra.com/errors/<code>`.                                                        |
| `title`      | The code in words, such as `scope missing`.                                                                                 |
| `status`     | The HTTP status, repeated in the body.                                                                                      |
| `detail`     | What happened in this request. Never carries personal data: handles, message text and documents stay out of error messages. |
| `code`       | The stable code from the catalog below.                                                                                     |
| `request_id` | The id of the request. Quote it when you contact support. Every response carries it, successful or not.                     |

## The catalog

| Code                       | Status | Python SDK                 | TypeScript SDK              | What to do                                                                                                                                                                                                                                                                                                                          |
| -------------------------- | ------ | -------------------------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `invalid_input`            | 422    | `UnprocessableEntityError` | `NiadraAPIError`            | The body does not match the contract: an unknown field, a missing required field, a value out of range, a feedback without the fields its action needs, a batch over 2.5 MB or 500 items. `detail` lists the field paths and error types, never the values you sent. Fix the request; retrying the same body gives the same answer. |
| `verification_not_allowed` | 422    | `UnprocessableEntityError` | `NiadraAPIError`            | A `verify` declared a level above the ceiling of your source. Automated agents stop at V2; V3 needs a source that runs OTP; V4 is for human desks and systems of record. Change the source in the Console, not the request.                                                                                                         |
| `about_without_link`       | 422    | `UnprocessableEntityError` | `NiadraAPIError`            | `about` named an account or partner with no active link to the person. The answer never says whether the organization exists. Create the link with [`POST /v1/identity/links`](/en/api/identity-links), or read without `about`.                                                                                                    |
| `unauthenticated`          | 401    | `AuthenticationError`      | `NiadraAuthenticationError` | The key is missing, malformed, rotated or revoked. Do not retry. The SDKs drop the cached context of that key on a 401.                                                                                                                                                                                                             |
| `forbidden`                | 403    | `PermissionDeniedError`    | `NiadraPermissionError`     | The key is valid but may not do this, or the access of its source was cut; or the Console person lacks a role of the route; or a `vendor` person asked about a source outside their binding.                                                                                                                                        |
| `scope_missing`            | 403    | `PermissionDeniedError`    | `NiadraPermissionError`     | The key lacks the scope of the route: `track`, `act`, `context`, `search`, `identify`, `admin` or `analytics`. Create a key with the scope.                                                                                                                                                                                         |
| `operation_not_allowed`    | 403    | `PermissionDeniedError`    | `NiadraPermissionError`     | An action used an operation or object type the `act` scope of this source does not allow.                                                                                                                                                                                                                                           |
| `not_found`                | 404    | `NotFoundError`            | `NiadraAPIError`            | The item, object or resource does not exist in this space, or the policy of your source does not let it be seen.                                                                                                                                                                                                                    |
| `conflict`                 | 409    | `ConflictError`            | `NiadraAPIError`            | The same `Idempotency-Key` was sent with a different body in the last 24 hours. Use a new key for a new request.                                                                                                                                                                                                                    |
| `wrong_cell`               | 421    | `WrongCellError`           | `NiadraAPIError`            | The space is moving between cells. Retry at once on a new connection; both SDKs do it for you.                                                                                                                                                                                                                                      |
| `rate_limited`             | 429    | `RateLimitError`           | `NiadraRateLimitError`      | Over the limit of your space or key. Wait the seconds in `Retry-After`. Reads are the last thing to be limited.                                                                                                                                                                                                                     |
| `internal_error`           | 500    | `ServerError`              | `NiadraAPIError`            | Something failed on our side. Retry with backoff and send the `request_id` if it persists.                                                                                                                                                                                                                                          |
| `unavailable`              | 503    | `ServerError`              | `NiadraAPIError`            | A dependency is temporarily out. Retry after `Retry-After`; writes stay in the SDK queue until then.                                                                                                                                                                                                                                |

A route that needs a person, such as review verdicts, answers 403 `forbidden` to a source key. See [Limits and conventions](/en/conventions) for the sizes.

In the Python SDK, `code` and `request_id` are properties of `APIError`, and `problem` holds the parsed body. In the TypeScript SDK, `NiadraAPIError` has `status`, `code`, `requestId` and `problem`.

## Errors inside a batch

[`POST /v1/batch`](/en/api/batch) answers 200 when every item went in and 207 when some items were rejected; [`POST /v1/feedback`](/en/api/feedback) and the [system webhook](/en/api/ingest-webhook) answer the same way. Item codes are the catalog codes plus `too_large`, for an item over 1 MB. One bad item never fails the batch: the valid items are stored and each rejected item comes back with its position.

```json theme={null}
{
  "accepted": 41,
  "duplicates": 2,
  "errors": [
    { "index": 7, "code": "invalid_input", "detail": "a system event needs `canonical_type`" },
    { "index": 19, "code": "verification_not_allowed", "detail": "level V4 is above the ceiling of this source" }
  ]
}
```

| Field        | Description                                                                          |
| ------------ | ------------------------------------------------------------------------------------ |
| `accepted`   | Items stored.                                                                        |
| `duplicates` | Items whose `idempotency_key` was already stored. Counted, never stored twice.       |
| `errors`     | One entry per rejected item: `index` (its position in `items`), `code` and `detail`. |

A duplicate is not an error: resending a batch after a timeout is safe. The SDKs log rejected items with their code and drop them, because the same item would be rejected again.

## Retries

| Answer                             | Reads (`context`, navigation)                                               | Writes (batch, identify, verify)                        |
| ---------------------------------- | --------------------------------------------------------------------------- | ------------------------------------------------------- |
| 421                                | Retried at once, inside the time budget                                     | Retried at once                                         |
| 429                                | Python: retried when `Retry-After` fits the budget. TypeScript: not retried | Retried after `Retry-After`                             |
| 500, 502, 503, 504, network errors | Python: retried with backoff inside the budget. TypeScript: not retried     | Retried with exponential backoff and jitter, 3 attempts |
| 408                                | Not retried                                                                 | TypeScript: retried like a 5xx. Python: final           |
| Any other 4xx                      | Final                                                                       | Final                                                   |

Both SDKs give reads a short total budget of their own, so a retry never makes the agent wait past it. In the default mode a failed read resolves with an empty or last good value, and the agent carries on without memory for that turn.

## Tracing a request

Send a W3C `traceparent` header and Niadra continues your trace; every response carries `request_id`. Quote the `request_id` when you contact us. The SDK errors expose it as `request_id` in Python and `requestId` in TypeScript.

## Next steps

<CardGroup cols={2}>
  <Card title="Limits and conventions" href="/en/conventions">
    idempotency, pagination, rate limits and sizes.
  </Card>

  <Card title="Python SDK" href="/en/sdk/python">
    the exception classes and strict mode.
  </Card>

  <Card title="TypeScript SDK" href="/en/sdk/typescript">
    the error classes and `Result`.
  </Card>

  <Card title="Send a batch" href="/en/api/batch">
    the 200 and 207 answers in the API reference.
  </Card>
</CardGroup>
