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

# Errors

> Typed errors thrown by the Superserve SDK and when to catch each one.

Every error raised by the SDK extends a common base class - `SandboxError` in TypeScript, `SandboxError` in Python - so you can catch it broadly or narrow down to a specific case.

## Error hierarchy

| TypeScript            | Python                | HTTP status | Meaning                                                                                                                                |
| --------------------- | --------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| `SandboxError`        | `SandboxError`        | -           | Base class for every SDK error.                                                                                                        |
| `AuthenticationError` | `AuthenticationError` | `401`       | Missing or invalid API key / access token.                                                                                             |
| `ValidationError`     | `ValidationError`     | `400`       | Request body or parameters rejected by the API.                                                                                        |
| `NotFoundError`       | `NotFoundError`       | `404`       | Sandbox or resource does not exist.                                                                                                    |
| `ConflictError`       | `ConflictError`       | `409`       | Sandbox is not in a valid state for the operation (e.g., pausing an already-paused sandbox, or patching `network` rules while paused). |
| `RateLimitError`      | `RateLimitError`      | `429`       | Rate limit or per-team quota reached. Branch on `code` (see below).                                                                    |
| `TimeoutError`        | `SandboxTimeoutError` | -           | Request or command timed out.                                                                                                          |
| `ServerError`         | `ServerError`         | `5xx`       | Platform error - usually transient (500/502/503/504). GET/DELETE requests auto-retry with exponential backoff.                         |

<Note>
  Python renames `TimeoutError` to `SandboxTimeoutError` so it doesn't shadow Python's built-in `TimeoutError`.
</Note>

## Catching a specific error

Catch the typed subclass you care about and fall back to `SandboxError` for everything else.

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
  import { NotFoundError, Sandbox, SandboxError } from "@superserve/sdk"

  try {
    const sandbox = await Sandbox.connect("missing-id")
  } catch (err) {
    if (err instanceof NotFoundError) {
      // Sandbox doesn't exist or was already deleted
    } else if (err instanceof SandboxError) {
      // Any other SDK error
    }
  }
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
  from superserve import NotFoundError, Sandbox, SandboxError

  try:
      sandbox = Sandbox.connect("missing-id")
  except NotFoundError:
      # Sandbox doesn't exist or was already deleted
      pass
  except SandboxError:
      # Any other SDK error
      pass
  ```
</CodeGroup>

## Base error properties

Every SDK error extends `SandboxError` and exposes:

* `statusCode?: number` / `status_code: int | None` - HTTP status, if the error originated from an API response
* `code?: string` / `code: str | None` - API-provided error code, when present

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
  import { Sandbox, SandboxError } from "@superserve/sdk"

  try {
    await Sandbox.connect("missing-id")
  } catch (err) {
    if (err instanceof SandboxError) {
      console.error(err.statusCode, err.code, err.message)
    }
  }
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
  from superserve import Sandbox, SandboxError

  try:
      Sandbox.connect("missing-id")
  except SandboxError as err:
      print(err.status_code, err.code, err)
  ```
</CodeGroup>

## Idempotent operations

`kill()` / `kill_by_id()` swallow `404` internally - it's safe to call on a sandbox that was already deleted by another process. Every other method surfaces `NotFoundError` to the caller.

## Retries

The SDK automatically retries transient failures on `GET` and `DELETE` requests with exponential backoff and jitter:

* `429 Too Many Requests`
* `5xx` server errors
* Network errors (connection reset, DNS failure)

`POST` / `PATCH` requests are **not** retried automatically because they aren't safely idempotent - the SDK surfaces the error so you can decide.

## `RateLimitError`

Raised on `429` responses. Branch on `code` to distinguish the variant:

| Code                 | Endpoint(s)       | Meaning                                                                               |
| -------------------- | ----------------- | ------------------------------------------------------------------------------------- |
| `rate_limited`       | any               | Request rate exceeded; retry after a short backoff.                                   |
| `too_many_builds`    | `POST /templates` | Team has reached its concurrent build limit. Wait for an active build to finish.      |
| `too_many_templates` | `POST /templates` | Team has reached its total template count limit. Delete one or contact support.       |
| `too_many_sandboxes` | `POST /sandboxes` | Team has reached its active sandbox count limit. Pause/delete one or contact support. |

The error `message` already includes the cap and a contact-support hint, so surfacing it directly to users is usually fine.

## `BuildError`

Raised by `Template.waitUntilReady()` / `wait_until_ready()` when the awaited build lands on status `failed`.

**Fields:**

* `code` - stable error prefix (`image_pull_failed`, `step_failed`, `boot_failed`, `snapshot_failed`, `start_cmd_failed`, `ready_cmd_failed`, `build_failed`)
* `buildId` / `build_id` - the build that failed
* `templateId` / `template_id` - the template id
* `message` - human-readable detail. The backend's `error_message` follows a `"<code>: <detail>"` convention (e.g. `"image_too_large: image is too large for the requested disk_mib"`); the SDK splits it so `code` holds the prefix and `message` holds the detail. When the backend doesn't include a prefix or message, `message` falls back to `"Template build failed"`.

See [BuildSpec reference: build error codes](/templates/build-spec#build-error-codes) for a full list of codes and their meanings.
