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

# Molecule Python SDK Error Handling and Exception Types

> The Molecule SDK maps API error codes to typed Python exceptions. Catch specific subclasses to handle auth failures, conflicts, and rate limits precisely.

The SDK raises typed exceptions whenever the API returns an error response. Every exception extends `MoleculeError`, so you can catch the base class for a broad handler or catch specific subclasses to handle individual failure modes precisely. All error classes are importable directly from the top-level `molecule` package.

## Error Hierarchy

```
MoleculeError                    # base class for all SDK errors
├── UnauthorizedError            # 401 — bad or expired signature
├── ForbiddenError               # 403 — access denied or wrong key type
├── NotFoundError                # 404 — resource not found
├── ConflictError                # 409 — duplicate or conflicting request
├── ValidationError              # 422 — invalid request parameters
├── RateLimitedError             # 429 — too many requests
├── BadRequestError              # 400 — malformed request
├── RoutingUnavailableError      # 400 ROUTING_UNAVAILABLE — no live venue
└── APIError                     # unexpected HTTP or payload error
```

## Error Attributes

Every `MoleculeError` instance carries four attributes that surface context from the API response.

| Attribute | Type | Description |
| - | - | - |
| `message` | `str` | Human-readable description of the error |
| `error` | `str \| None` | Machine-readable API error code (e.g. `"idempotency_conflict"`) |
| `status_code` | `int \| None` | HTTP status code returned by the API |
| `details` | `Any` | Additional context from the API response, if present |

Access these attributes on any caught exception:

```python theme={"dark"}
from molecule import Molecule, ConflictError, UnauthorizedError

try:
    order = client.create_order(
        subaccount_id="sub-1",
        instrument_id="instrument-abc",
        side="BUY",
        type="LIMIT",
        tif="GTC",
        price="0.50",
        qty="10",
        routing={"mode": "DIRECT"},
        client_order_id="my-order-1",
    )
except ConflictError as e:
    print(e.error)       # "idempotency_conflict"
    print(e.status_code) # 409
    print(e.message)     # human-readable message
    print(e.details)     # additional context from API
```

## Error Code Reference

| Error class | HTTP status | API error codes | When it occurs |
| - | - | - | - |
| `UnauthorizedError` | 401 | `unauthorized`, `signature`, `replay`, `stale_timestamp` | Bad or expired signature; request outside 30-second replay window |
| `ForbiddenError` | 403 | `forbidden`, `human_session_required`, `kill_switch` | Access denied; endpoint requires a human session; kill-switch is active |
| `NotFoundError` | 404 | `not_found` | The requested resource does not exist |
| `ConflictError` | 409 | `conflict`, `idempotency_conflict` | Duplicate order submitted; same idempotency key used with a different request body |
| `ValidationError` | 422 | `validation` | Invalid or missing request parameters |
| `RateLimitedError` | 429 | `rate_limited` | Request rate exceeds allowed limits |
| `RoutingUnavailableError` | 400 | `ROUTING_UNAVAILABLE`, `routing_unavailable` | No live venue is available to route the order |
| `BadRequestError` | 400 | *(other)* | Malformed request not covered by a more specific error code |
| `APIError` | *(other)* | — | Unexpected HTTP error or unparseable response payload |

## Handling Common Cases

The following pattern covers the most common failure modes when submitting orders. Adapt the retry and fallback logic to your execution requirements.

```python theme={"dark"}
import time
from molecule import (
    Molecule,
    ConflictError,
    RateLimitedError,
    RoutingUnavailableError,
    UnauthorizedError,
)

try:
    order = client.create_order(
        subaccount_id="sub-1",
        instrument_id="instrument-abc",
        side="BUY",
        type="LIMIT",
        tif="GTC",
        price="0.50",
        qty="10",
        routing={"mode": "DIRECT"},
        client_order_id="my-order-1",
    )
except ConflictError as e:
    if e.error == "idempotency_conflict":
        # Same client_order_id submitted with different parameters — raise to surface the bug
        raise
    # Otherwise the same order already exists — safe to proceed
except RateLimitedError:
    time.sleep(1)
    # retry
except RoutingUnavailableError:
    # No venue available — check venue health before retrying
    health = client.markets.venue_health()
    print(health)
except UnauthorizedError as e:
    # Verify key_id and private_key configuration
    raise
```

<Note>
  All error classes — including `MoleculeError` and every subclass — are exported from the top-level `molecule` package. Import them with `from molecule import UnauthorizedError, ConflictError, ...` rather than from internal submodules.
</Note>


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