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

# Errors

> Every HTTP status code the ZeroDrift Enforcement API returns, and what to do.

HTTP errors return JSON. Responses generated by the API gateway use a top-level
`message` field:

```json theme={null}
{
  "message": "Forbidden"
}
```

Validation and application errors may instead use a top-level `detail` field.
Read either field when presenting an error to an operator.

| Code  | Meaning                                                                                                  | What to do                                                                                                                                                 |
| ----- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400` | Bad request, such as invalid parameters, training options, pagination, or an Activity range over 30 days | Correct the field named in the response.                                                                                                                   |
| `401` | Invalid API key on the Activity API                                                                      | Check the `x-api-key` header and the key in Command.                                                                                                       |
| `403` | Missing, invalid, inactive, or unresolved API key; or a key without permission for the operation         | Check the key, or use a full-access key for write operations.                                                                                              |
| `404` | Unknown `job_id`, `import_id`, `rule_id`, `activity_id`, or rulepack selector                            | Check the id. Jobs and activities age out according to [Data Retention](/data-retention).                                                                  |
| `409` | Resource-state conflict, such as an import that is not activated or a training run already in progress   | Complete the required state transition or wait for the active operation.                                                                                   |
| `410` | The original policy document expired                                                                     | Re-import and activate the policy, then retry training.                                                                                                    |
| `413` | An uploaded policy is too large                                                                          | Use a smaller document or the supported presigned-upload limits.                                                                                           |
| `422` | Content, a policy document, or request fields could not be processed                                     | Correct or provide fuller input.                                                                                                                           |
| `429` | Rate limit exceeded                                                                                      | Retry with backoff. The standard limit is 10 requests per second with a burst of 50.                                                                       |
| `500` | Internal server error                                                                                    | Follow the endpoint-specific guidance. Some operations are safe to retry; `POST /api/policies/import/start` must not be retried with the same `import_id`. |
| `502` | Training Studio upstream request failed                                                                  | Retry with backoff.                                                                                                                                        |
| `503` | Training is not enabled, or the service is temporarily unavailable                                       | For temporary failures, retry. For a disabled feature, contact support.                                                                                    |

The exact set varies by endpoint. Each endpoint page lists the statuses that it
returns, and the [OpenAPI specification](/api-reference/openapi) is the
machine-readable contract.

## Retry pattern

Retry only transient failures and rate limits:

```python theme={null}
import time

import requests


def call_with_retry(send, retryable_statuses, attempts=4):
    response = None
    for attempt in range(attempts):
        response = send()
        if response.status_code not in retryable_statuses:
            return response

        if attempt == attempts - 1:
            break

        retry_after = response.headers.get("Retry-After")
        delay = float(retry_after) if retry_after else min(2**attempt, 8)
        time.sleep(delay)

    return response
```

Choose `retryable_statuses` from the endpoint's documented responses. For
example, pass `{429, 500, 502, 503}` only when that operation is safe to repeat.
For `POST /api/policies/import/start`, do not include `500`: create a new upload
and `import_id` before trying again.

Do not retry `400`, `401`, `403`, `404`, `409`, `410`, `413`, or `422`
without changing the request or resource state. Never re-send content that
received a Block verdict.

## Job failures are not HTTP errors

An asynchronous enforcement job can finish with `status: "failed"`. In that
case, the `error` field on the job explains the failure while the poll request
itself returns HTTP `200`.

```json theme={null}
{
  "api_version": "v3",
  "job_id": "a1b2c3",
  "status": "failed",
  "model_engine": "anchor_3_0",
  "error": "Validation engine unavailable"
}
```
