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

# Errors

> Typed error classes, retry behavior, and status code mapping.

All SDK errors extend `VerialError`. API errors extend `APIError` with a numeric `status`, a string `code`, and an optional `requestId` captured from the response.

## Hierarchy

```
VerialError
├── APIError
│   ├── AuthenticationError       401
│   ├── PermissionDeniedError     403
│   ├── NotFoundError             404
│   ├── ConflictError             409
│   ├── ValidationError           400 (and other 4xx not covered above)
│   ├── RateLimitError            429 (with retryAfter)
│   └── InternalServerError       5xx
├── APIConnectionError            network / fetch failure
└── APITimeoutError               request exceeded timeout
```

## Fields

Every `APIError` exposes:

| Field       | Type                 | Description                                                          |
| ----------- | -------------------- | -------------------------------------------------------------------- |
| `status`    | number               | HTTP status code                                                     |
| `code`      | string               | Machine-readable error code from the API (e.g. `RESOURCE_NOT_FOUND`) |
| `message`   | string               | Human-readable message. Includes `(request_id: ...)` when provided.  |
| `requestId` | string \| undefined  | Request ID — include this when filing support tickets.               |
| `headers`   | Headers \| undefined | Response headers                                                     |
| `errors`    | object \| undefined  | Field-level validation details for `ValidationError`                 |

`RateLimitError` additionally exposes:

| Field        | Type                | Description                                                    |
| ------------ | ------------------- | -------------------------------------------------------------- |
| `retryAfter` | number \| undefined | Seconds until the next retry, parsed from `Retry-After` header |

## Catching

```typescript theme={null}
import {
  APIError,
  AuthenticationError,
  NotFoundError,
  RateLimitError,
  ValidationError,
} from '@verial-ai/sdk'

try {
  await verial.environments.get({ id: 'env_does_not_exist' })
} catch (err) {
  if (err instanceof NotFoundError) {
    // 404 — resource does not exist
  } else if (err instanceof AuthenticationError) {
    // 401 — bad API key
  } else if (err instanceof RateLimitError) {
    await sleep((err.retryAfter ?? 1) * 1000)
  } else if (err instanceof ValidationError) {
    console.error('validation', err.errors)
  } else if (err instanceof APIError) {
    // any other 4xx/5xx
    console.error(err.status, err.code, err.requestId)
  } else {
    throw err
  }
}
```

## Retry Behavior

The SDK automatically retries these statuses with exponential backoff + jitter:

* `408` Request Timeout
* `429` Too Many Requests (honors `Retry-After`)
* `500` / `502` / `503` / `504`

It also retries network errors (`APIConnectionError`). `APITimeoutError` is not retried — it surfaces immediately so callers can decide.

Retries default to **2** (3 total attempts). Override with `maxRetries`:

```typescript theme={null}
const verial = new Verial({ apiKey, maxRetries: 5 })
```

Backoff: `min(0.5 * 2^attempt, 8)` seconds with ±20% jitter. `Retry-After` on 429 overrides the backoff.

## Timeouts

Requests time out after `60000` ms by default. Override per-client:

```typescript theme={null}
const verial = new Verial({ apiKey, timeout: 10_000 })
```

A timeout throws `APITimeoutError` immediately without retrying.
