> ## 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"
  }
}
```

**error.type** `string`

Coarse class tied to the HTTP status (see below). SDKs subclass their exception types on `type`.

**error.code** `string`

Stable, machine-branchable string. **Switch on this** — it is the one taxonomy that never changes meaning.

**error.message** `string`

Human-readable explanation. Do not parse.

**error.request\_id** `string`

The id of the failing request (matches the `x-request-id` response header). Quote it in support requests.

**error.param** `string | null`

The request field that caused the error, when the failure is attributable to one.

> [!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](https://vetta.sh/docs/api/overview.md#request-ids).

## Types

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

| Type | HTTP |
| - | - |
| `invalid_request` | 400, or 405 for `method_not_allowed` |
| `authentication` | 401 |
| `quota` | 402 |
| `permission` | 403 |
| `not_found` | 404 |
| `conflict` | 409 |
| `rate_limit` | 429 |
| `api_error` | 500, or 502 when the failure was an upstream's |
| `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](https://vetta.sh/docs/concepts/completion-window.md). |
| `unauthorized` | `authentication` | 401 | Missing or invalid API key. |
| `budget_exceeded` | `quota` | 402 | The call would breach an agent/session/org [budget](https://vetta.sh/docs/api/credits.md). |
| `insufficient_credits` | `quota` | 402 | The org's [credit balance](https://vetta.sh/docs/api/credits.md) is too low to cover the call. |
| `subscription_required` | `quota` | 402 | The org holds no active [plan](https://vetta.sh/docs/api/credits.md). 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](https://vetta.sh/docs/api/agents.md) denied the action. |
| `not_found` | `not_found` | 404 | The resource does not exist in this organization. |
| `method_not_allowed` | `invalid_request` | 405 | The path exists but does not serve this method. The `Allow` header lists the methods it does. |
| `version_conflict` | `conflict` | 409 | Optimistic-concurrency mismatch on an [agent update](https://vetta.sh/docs/api/agents.md): the `expected_version` is stale. Also a [database migration](https://vetta.sh/docs/api/database.md) re-applied under an existing name with different SQL. |
| `ambiguous_app` | `conflict` | 409 | A [database](https://vetta.sh/docs/api/database.md) or [storage](https://vetta.sh/docs/api/storage.md) call named no app and the organization holds several `fullstack` apps; the message lists the candidate ids — pass `app`. |
| `revision_conflict` | `conflict` | 409 | A shared declaration moved underneath an [apply](https://vetta.sh/docs/api/apps.md#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](https://vetta.sh/docs/api/apps.md). |
| `idempotency_conflict` | `conflict` | 409 | An `Idempotency-Key` was replayed with a different body. See the [overview](https://vetta.sh/docs/api/overview.md#idempotency). |
| `state_conflict` | `conflict` | 409 | A lifecycle action the object's current status does not admit — forming a company on an unverified [verification](https://vetta.sh/docs/api/legal.md), writing to a frozen [wallet](https://vetta.sh/docs/api/wallet.md), cancelling a [card](https://vetta.sh/docs/api/cards.md) that is not active. Read the status and act on what it says. |
| `session_running` | `conflict` | 409 | Input was sent to a running [session](https://vetta.sh/docs/api/sessions.md) without `interrupt`. |
| `session_terminal` | `conflict` | 409 | The [session](https://vetta.sh/docs/api/sessions.md) has already ended and cannot accept input. |
| `computer_unavailable` | `conflict` | 409 | The requested [computer](https://vetta.sh/docs/api/computers.md) 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. |
| `context_locked` | `conflict` | 409 | A saved [browser login](https://vetta.sh/docs/api/browser.md#save-a-login) is held for a person's sign-in (`human_login`) for up to 15 minutes; saving it releases the lock. Retry after `locked_until`. |
| `rate_limited` | `rate_limit` | 429 | Too many requests; back off and retry after `Retry-After`. |
| `provider_error` | `api_error` | 502 | An upstream capability the call depended on (a [browser](https://vetta.sh/docs/api/browser.md) `act`, a generation model, the [audio](https://vetta.sh/docs/api/audio.md) provider, a stock library, or a step of an asynchronous job such as a [clip](https://vetta.sh/docs/api/clips.md)) failed or reported that nothing happened. Nothing was billed; retry with backoff (the same `Idempotency-Key` is safe), or fall back to a deterministic action. |
| `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.

### 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
  }
}
```

> [!NOTE]
>
> 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](https://vetta.sh/docs/api/overview.md#idempotency).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.