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

# Errors

> HTTP status codes Karta returns, what each means, and how errors surface mid-stream.

Karta uses conventional HTTP status codes. Agent runtime routes return the body
under a `detail` key - a string for simple errors, or an object carrying an
`error` code and `message` for structured ones. The session-token mint endpoint
returns those same fields flat, without the `detail` wrapper.

## Status codes

| Status | Meaning                                                                                                                                                                                                | Body                                                                                  |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- |
| `200`  | Success - accumulated response, or the start of an SSE stream.                                                                                                                                         | response object / SSE                                                                 |
| `201`  | Resource created - a release, or a Managed Agents session. (Native session create returns `200`.)                                                                                                      | the resource                                                                          |
| `202`  | Accepted - async work queued (e.g. a Managed Agents event).                                                                                                                                            | `{ "accepted": true }`                                                                |
| `401`  | Missing or invalid credential.                                                                                                                                                                         | `{ "detail": "Unauthorized" }`                                                        |
| `402`  | Budget exhausted - the turn is blocked, or an over-budget org is refused a token mint.                                                                                                                 | `{ "detail": { "error": "budget_exhausted", ... } }` (see below)                      |
| `403`  | Forbidden - a metadata end-user id that conflicts with the verified token (`identity_mismatch`), or an API key lacking the required scope.                                                             | `{ "detail": "..." }`                                                                 |
| `404`  | Not found (unknown agent or no active release), belongs to another org, or a session token scoped to another agent - all shaped identically (default-deny), so the URL space is never a tenant oracle. | `{ "detail": "..." }`                                                                 |
| `409`  | Conflict - a release exists but is not materialized.                                                                                                                                                   | `{ "detail": "..." }`                                                                 |
| `422`  | Validation failed, or a BYOK key was rejected by the provider.                                                                                                                                         | `{ "detail": { "error": "byok_key_rejected", "provider": "...", "message": "..." } }` |
| `429`  | Too many requests - a rate limit was reached.                                                                                                                                                          | `{ "detail": "..." }` + optional `Retry-After`                                        |
| `503`  | Service unavailable - temporary; back off and retry.                                                                                                                                                   | `{ "detail": "..." }` + `Retry-After`                                                 |

## 402 - budget exhausted

When an org hits a [budget cap](/platform/usage-and-budgets), the agent runtime
returns `402` **before** running the turn. The payload sits under `detail`:

```json theme={null}
{ "detail": { "error": "budget_exhausted", "message": "Organization budget exceeded", "reason": "total_tokens_cap_reached" } }
```

Minting a [session token](/security/session-tokens) is gated the same way:
`POST /api/agents/{slug}/session_tokens` returns `402` when the org is over
budget, so an over-budget org cannot hand a fresh token to its browser clients.
That endpoint returns the same fields flat (no `detail` wrapper):

```json theme={null}
{ "error": "budget_exhausted", "message": "Organization budget exceeded", "reason": "subscription_past_due" }
```

The fields are identical on both paths: a stable `error` code, a human
`message`, and a `reason` machine code naming what tripped:
`credits_exhausted` (a managed org's prepaid balance is empty),
`total_tokens_cap_reached` (a configured token cap), or
`subscription_past_due`. Match on the `402` status; treat `error` as the
stable code and `reason` as diagnostic detail.

A per-instance or per-seat [cap](/platform/usage-and-budgets#karta-grain-caps)
returns `402` with a different `error` code - `instance_spend_cap_exceeded` -
rather than `budget_exhausted`.

## Errors during a stream

Once an SSE stream has started (`200` already sent), failures arrive as an
[`error` event](/concepts/streaming-events#error) rather than an HTTP status -
because the status line is already on the wire:

```text theme={null}
event: error
data: {"type":"error","data":{"code":"byok_key_rejected","provider":"anthropic","message":"invalid api key"}}
```

So a client must handle two failure channels: the HTTP status for pre-stream
problems (auth, budget, validation), and `error` events for mid-stream problems
(provider rejection, harness failure).

## 429, 503, and retries

For `429`, back off and retry. If a `Retry-After` header is present, honor it;
otherwise use exponential backoff with jitter.

A `503` means Karta is temporarily unable to serve the request (for example,
the harness is briefly unavailable). It carries a `Retry-After` header - back
off and retry, honoring `Retry-After`.

For support or correlation, keep the request timestamp, route, agent slug,
session id, and any response headers your client receives.
