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

# Wrenn SDK Error Types and HTTP Status Codes

> All Wrenn SDK errors inherit from WrennError and expose .code, .message, and .status_code. Use typed exceptions to handle specific failure modes.

The Wrenn SDK maps every HTTP error response to a typed Python exception. Instead of inspecting raw status codes, you catch the specific exception class that matches the failure — or catch the base `WrennError` to handle all API errors in one place.

## Base class

All SDK exceptions inherit from `WrennError`. Every instance exposes three attributes:

| Attribute      | Type  | Description                                                   |
| -------------- | ----- | ------------------------------------------------------------- |
| `.code`        | `str` | Machine-readable error code from the API (e.g. `"not_found"`) |
| `.message`     | `str` | Human-readable description of what went wrong                 |
| `.status_code` | `int` | HTTP status code of the response                              |

## Error reference

| Exception                   | HTTP Status | Error Code                  | When it occurs                                        |
| --------------------------- | ----------- | --------------------------- | ----------------------------------------------------- |
| `WrennValidationError`      | 400         | `invalid_request`           | Bad or missing request parameters                     |
| `WrennAuthenticationError`  | 401         | `unauthorized`              | Invalid or missing API key                            |
| `WrennForbiddenError`       | 403         | `forbidden`                 | Authenticated but not authorized for this resource    |
| `WrennNotFoundError`        | 404         | `not_found`                 | The requested resource does not exist                 |
| `WrennConflictError`        | 409         | `invalid_state`, `conflict` | Resource is in a state that prevents the operation    |
| `WrennHostHasCapsulesError` | 409         | `host_has_capsules`         | Host still has running capsules and cannot be removed |
| `WrennHostUnavailableError` | 503         | `host_unavailable`          | No suitable host is available to fulfill the request  |
| `WrennAgentError`           | 502         | `agent_error`               | The host agent returned an error                      |
| `WrennInternalError`        | 500         | `internal_error`            | Unexpected server-side error                          |

### WrennHostHasCapsulesError

`WrennHostHasCapsulesError` is a subclass of `WrennConflictError` and adds one extra attribute:

| Attribute      | Type        | Description                                   |
| -------------- | ----------- | --------------------------------------------- |
| `.capsule_ids` | `list[str]` | IDs of the capsules still running on the host |

Use `.capsule_ids` to destroy or pause the blocking capsules before retrying.

## Catching errors

### Catch all API errors

Use `WrennError` as a catch-all when you want to handle any API failure uniformly:

```python theme={null}
from wrenn import WrennError

try:
    result = capsule.commands.run("python script.py")
except WrennError as e:
    print(f"API error {e.status_code} [{e.code}]: {e.message}")
```

### Catch specific errors

Import and catch the typed exception you expect:

```python theme={null}
from wrenn import Capsule, WrennNotFoundError

try:
    capsule = Capsule.connect("cl-abc123")
except WrennNotFoundError:
    print("That capsule no longer exists.")
```

### Handle multiple error types

You can match multiple exception types in a single `try` block:

```python theme={null}
from wrenn import (
    WrennError,
    WrennAuthenticationError,
    WrennNotFoundError,
    WrennHostHasCapsulesError,
    WrennValidationError,
)

try:
    capsule.commands.run("./deploy.sh")
except WrennAuthenticationError:
    print("Check your WRENN_API_KEY — the request was not authenticated.")
except WrennNotFoundError:
    print("Capsule not found. It may have been destroyed.")
except WrennHostHasCapsulesError as e:
    print(f"Host is still running capsules: {e.capsule_ids}")
except WrennValidationError as e:
    print(f"Bad request: {e.message}")
except WrennError as e:
    # Fallback for any other API error
    print(f"Unexpected error [{e.code}]: {e.message}")
```

<Tip>
  Always place more specific exception types before the base `WrennError` catch. Python evaluates `except` clauses in order, so a broad catch placed first will swallow the typed ones below it.
</Tip>

## Importing exceptions

All exception classes are importable directly from the `wrenn` package:

```python theme={null}
from wrenn import (
    WrennError,
    WrennValidationError,
    WrennAuthenticationError,
    WrennForbiddenError,
    WrennNotFoundError,
    WrennConflictError,
    WrennHostHasCapsulesError,
    WrennHostUnavailableError,
    WrennAgentError,
    WrennInternalError,
)
```
