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

# Errors

> The typed error envelope and every error code.

The API uses conventional HTTP status codes and returns **exactly one JSON error envelope** on every failure. Inspect `error.code` for programmatic handling; `error.message` is human-readable and may change.

## Error envelope

```json theme={"system"}
{
  "error": {
    "type": "invalid_request",
    "code": "window_unavailable",
    "message": "The selected model does not support the 'loose' completion window.",
    "request_id": "req_01H8XK2M...",
    "param": "window"
  }
}
```

<ResponseField name="error.type" type="string">Coarse class tied to the HTTP status (see below). SDKs subclass their exception types on `type`.</ResponseField>
<ResponseField name="error.code" type="string">Stable, machine-branchable string. **Switch on this** — it is the one taxonomy that never changes meaning.</ResponseField>
<ResponseField name="error.message" type="string">Human-readable explanation. Do not parse.</ResponseField>
<ResponseField name="error.request_id" type="string">The id of the failing request (matches the `x-request-id` response header). Quote it in support requests.</ResponseField>
<ResponseField name="error.param" type="string | null">The request field that caused the error, when the failure is attributable to one.</ResponseField>

<Note>
  `request_id` is returned on **every** response — success and error — via the `x-request-id` header. On errors it is also mirrored inside the envelope. See the [overview](/docs/api/overview#request-ids).
</Note>

## Types

`type` is the coarse class and maps one-to-one onto the HTTP status. SDKs subclass their exception hierarchy on it.

| Type              | HTTP |
| ----------------- | ---- |
| `invalid_request` | 400  |
| `authentication`  | 401  |
| `quota`           | 402  |
| `permission`      | 403  |
| `not_found`       | 404  |
| `conflict`        | 409  |
| `rate_limit`      | 429  |
| `api_error`       | 500  |
| `not_implemented` | 501  |

## Codes

`code` is the stable, machine-branchable string. Branch on it; it never changes meaning across versions.

| Code                     | Type              | HTTP | Meaning                                                                                                                                                                        |
| ------------------------ | ----------------- | ---- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `validation_failed`      | `invalid_request` | 400  | The request was malformed or failed validation.                                                                                                                                |
| `window_unavailable`     | `invalid_request` | 400  | The model does not support the requested [completion window](/docs/concepts/completion-window).                                                                                     |
| `unauthorized`           | `authentication`  | 401  | Missing or invalid API key.                                                                                                                                                    |
| `budget_exceeded`        | `quota`           | 402  | The call would breach an agent/session/org [budget](/docs/api/credits).                                                                                                             |
| `insufficient_credits`   | `quota`           | 402  | The org's [credit balance](/docs/api/credits) is too low to cover the call.                                                                                                         |
| `subscription_required`  | `quota`           | 402  | The org holds no active [plan](/docs/api/credits). Start or renew it with `POST /v1/credits/subscription`.                                                                          |
| `forbidden`              | `permission`      | 403  | The key or member lacks the required scope/role, or a [permission policy](/docs/api/agents) denied the action.                                                                      |
| `not_found`              | `not_found`       | 404  | The resource does not exist in this organization.                                                                                                                              |
| `version_conflict`       | `conflict`        | 409  | Optimistic-concurrency mismatch on an [agent update](/docs/api/agents): the `expected_version` is stale.                                                                            |
| `revision_conflict`      | `conflict`        | 409  | A shared declaration moved underneath an [apply](/docs/api/apps#apply): the install's `revision` is not the `expected_revision` you sent. The message names the paths that drifted. |
| `name_conflict`          | `conflict`        | 409  | The name is held by a resource another `project` owns, and the request did not ask to `adopt` it. See [Apps](/docs/api/apps).                                                       |
| `idempotency_conflict`   | `conflict`        | 409  | An `Idempotency-Key` was replayed with a different body. See the [overview](/docs/api/overview#idempotency).                                                                        |
| `session_running`        | `conflict`        | 409  | Input was sent to a running [session](/docs/api/sessions) without `interrupt`.                                                                                                      |
| `session_terminal`       | `conflict`        | 409  | The [session](/docs/api/sessions) has already ended and cannot accept input.                                                                                                        |
| `computer_unavailable`   | `conflict`        | 409  | The requested [computer](/docs/api/computers) is not ready or has failed.                                                                                                           |
| `job_not_ready`          | `conflict`        | 409  | Nothing is wrong — the work is not ready yet. Retry.                                                                                                                           |
| `compliance_pending`     | `conflict`        | 409  | The action waits on a verification or carrier approval that has not cleared. Retry later.                                                                                      |
| `rate_limited`           | `rate_limit`      | 429  | Too many requests; back off and retry after `Retry-After`.                                                                                                                     |
| `internal_error`         | `api_error`       | 500  | Something failed on our side. Retry with backoff; the `request_id` is what to quote.                                                                                           |
| `feature_not_configured` | `not_implemented` | 501  | The feature is recognized but not configured for this organization.                                                                                                            |

<Note>
  `version_conflict` **is** a returned error: agent updates use optimistic concurrency, so a stale `expected_version` fails with `409`. Refetch `current_version` and re-apply your change.
</Note>

### The four `409`s are four different remedies

A `409` is not one thing, and the code is what tells you which. `version_conflict` means one versioned object is stale — re-read it and re-apply. `revision_conflict` means a whole shared declaration moved — merge, using the paths the message names. `name_conflict` means somebody else owns the name — pick another or `adopt`. `job_not_ready` and `compliance_pending` mean nothing is wrong at all — **retry**, and a client that treats them as terminal gives up on work that was going to succeed.

## Handling errors

Retry `429` and transient `5xx` responses with exponential backoff, honoring `Retry-After` on `429`. Treat `400`, `401`, `402`, `403`, and `404` as terminal — fix the request or credentials rather than retrying. **Branch a `409` on its `code`, never on the status** — two of them are retryable and the rest are not.

```typescript theme={"system"}
const res = await fetch(url, options);
if (!res.ok) {
  const { error } = await res.json();
  switch (error.code) {
    case "version_conflict": // refetch current_version and retry
    case "revision_conflict": // the declaration moved: merge on error.message's paths, re-apply
    case "name_conflict":    // another project owns the name: rename, or re-send with adopt
    case "job_not_ready":    // not an error — back off and retry
    case "compliance_pending": // not an error — retry once verification clears
    case "rate_limited":     // back off and honor Retry-After
    case "subscription_required": // send the customer to POST /v1/credits/subscription
    case "insufficient_credits": // top up credits, then retry
    case "budget_exceeded":  // raise the cap or top up credits
    default:                 // surface error.message + error.request_id
  }
}
```

<Info>
  Every mutation accepts an `Idempotency-Key`, so retrying a request that failed with a network error or `429` will not double-apply. See the [overview](/docs/api/overview#idempotency).
</Info>
