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

> ## Agent Instructions
> Krun API base URL: https://api.krun.ai. Authenticate server-side with `Authorization: Bearer $KRUN_API_KEY`; never put a Krun API key in browser code.
> Prefer the Python SDK in examples: `pip install krun-ai`, `from krun import Krun`. The TypeScript SDK `@krun-ai/sdk` is not published on npm yet: do not tell users to `npm install` it.
> The only question type is `choice`. `confidence` is the top-1 minus top-2 probability margin, not the probability that the answer is correct. `choice` is null when `abstain` is true.
> Usage reports `input_tokens` only. There are no output tokens.

# Errors

> Krun API error format, error codes, HTTP status codes and which errors to retry.

Every error has the same JSON shape, with a stable machine-readable `code`:

```json theme={null}
{
  "error": {
    "code": "INVALID_OPTIONS",
    "message": "questions.department: 1 options given; between 2 and 64 are required",
    "request_id": "req_0b7f7c5e9a3d4a8c9f1e2d3c4b5a6978"
  }
}
```

| Field        | Description                                                                          |
| ------------ | ------------------------------------------------------------------------------------ |
| `code`       | Stable error code. Branch on this, not on `message`.                                 |
| `message`    | Human-readable explanation. The wording can change.                                  |
| `request_id` | Id of the failed request. Include it when you [contact support](/resources/support). |

## Error codes

| Code                   | HTTP | Meaning                                                                                                             | Retry               |
| ---------------------- | ---- | ------------------------------------------------------------------------------------------------------------------- | ------------------- |
| `INVALID_REQUEST`      | 400  | The request is malformed: missing or unknown fields, wrong types, empty context, too many questions, duplicate ids. | No                  |
| `INVALID_OPTIONS`      | 400  | A question's options are invalid, for example fewer than 2 or more than 64.                                         | No                  |
| `UNAUTHORIZED`         | 401  | Missing, invalid or revoked API key.                                                                                | No                  |
| `NOT_FOUND`            | 404  | Unknown path, or feedback for a `request_id` your project never decided.                                            | No                  |
| `PAYLOAD_TOO_LARGE`    | 413  | The request body is larger than 256 KiB.                                                                            | No                  |
| `RATE_LIMITED`         | 429  | The API key's per-minute rate limit was reached.                                                                    | After `Retry-After` |
| `QUOTA_EXCEEDED`       | 429  | The project's monthly quota is exhausted.                                                                           | No                  |
| `INTERNAL_ERROR`       | 500  | Unexpected error in the API.                                                                                        | No                  |
| `INFERENCE_FAILED`     | 502  | The model backend failed to produce a valid answer.                                                                 | Yes, with backoff   |
| `UPSTREAM_UNAVAILABLE` | 503  | The model backend is temporarily unavailable. Sent with `Retry-After`.                                              | Yes, with backoff   |
| `UPSTREAM_TIMEOUT`     | 504  | The model backend did not answer within the API's deadline, for example during a slow cold start.                   | Yes, with backoff   |

A request with a wrong HTTP method keeps its `405` status and uses the `INVALID_REQUEST` code.

Invalid requests (`400` and `413`) are rejected before any inference runs, and don't count toward quotas.

## Retrying

* Retry `502`, `503`, `504` and connection errors with exponential backoff and jitter. Honor `Retry-After` when present. Keep retries few: the API already retries its model backend.
* For `429 RATE_LIMITED`, wait for the number of seconds in `Retry-After` before sending more requests.
* Don't retry `400`, `401`, `404`, `413` or `429 QUOTA_EXCEEDED` automatically: the same request will fail again.
* `500 INTERNAL_ERROR` is not retried by the SDK. If it persists, [contact support](/resources/support) with the request id.

See [Production best practices](/guides/production-best-practices#retries).

## Errors in the Python SDK

The Python SDK raises one exception class per code, and retries `502`, `503` and `504` once by default:

| Code                                                      | Exception                 |
| --------------------------------------------------------- | ------------------------- |
| `INVALID_REQUEST`, `INVALID_OPTIONS`, `PAYLOAD_TOO_LARGE` | `InvalidRequestError`     |
| `UNAUTHORIZED`                                            | `AuthenticationError`     |
| `NOT_FOUND`                                               | `NotFoundError`           |
| `RATE_LIMITED`                                            | `RateLimitError`          |
| `QUOTA_EXCEEDED`                                          | `QuotaExceededError`      |
| `INFERENCE_FAILED`                                        | `InferenceFailedError`    |
| `UPSTREAM_UNAVAILABLE`                                    | `ServiceUnavailableError` |
| `UPSTREAM_TIMEOUT`                                        | `UpstreamTimeoutError`    |
| `INTERNAL_ERROR`                                          | `InternalServerError`     |

All of them inherit from `krun.APIError` and `krun.KrunError`, and carry `error_code`, `status_code`, `message` and `request_id`. See [Python SDK errors](/sdks/python#errors).
