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

# Error Handling

> Retry behavior, timeouts, and error handling in the Python SDK.

The Python SDK handles transient failures automatically and surfaces real errors clearly.

## Retry behavior

The SDK retries requests that fail with transient HTTP statuses:

<ParamField body="retried_statuses" type="list[int]" default="[429, 500, 502, 503]">
  HTTP status codes that trigger an automatic retry.
</ParamField>

<ParamField body="max_retries" type="int" default="3">
  Maximum number of retry attempts before raising.
</ParamField>

<ParamField body="backoff" type="float" default="0.5 × 2^attempt seconds">
  Exponential backoff between retries. First retry waits 0.5 s, second 1 s, third 2 s.
</ParamField>

<ParamField body="timeout" type="float" default="30.0">
  Request timeout in seconds. Configurable on the client.
</ParamField>

## Token refresh

On `401 Unauthorized`, the SDK refreshes the access token once and retries the request. You do not manage tokens yourself.

## Configuring timeout

```python theme={"dark"}
from hexel import Hexel

client = Hexel(api_key="YOUR_API_KEY", timeout=60.0)
```

## Handling errors

After exhausting retries, the SDK raises `httpx.HTTPStatusError`. Catch it to inspect the status and body:

```python theme={"dark"}
import httpx
from hexel import Hexel

client = Hexel(api_key="YOUR_API_KEY")

try:
    instances = client.compute.instance.list(agent_id="YOUR_AGENT_ID")
except httpx.HTTPStatusError as e:
    print(f"Status {e.response.status_code}: {e.response.text}")
except httpx.TimeoutException:
    print("Request timed out")
```

## Handling tool execution errors

```python theme={"dark"}
import httpx
from hexel import Hexel

client = Hexel(api_key="YOUR_API_KEY")

try:
    result = client.tools.execute(
        tool_slug="GMAIL_SEND_EMAIL",
        input={"to": "user@example.com", "subject": "Test", "body": "Hello"},
    )
except httpx.HTTPStatusError as e:
    if e.response.status_code == 422:
        print("Invalid input:", e.response.text)
    else:
        print(f"Tool execution failed: {e.response.status_code}")
```

## Common mistakes

* **Adding your own retry loop on top of the SDK.** This compounds backoff; rely on the built-in retries.
* **Treating `429` as fatal.** It is retried automatically; only persistent rate limiting surfaces as an error.

## Best practices

* Catch `httpx.HTTPStatusError` to inspect status and body.
* Raise the timeout for known long-running operations rather than retrying.
* Use idempotency keys for [tool executions](/docs/tool-gateway/execution) you may retry.

## Related pages

<CardGroup cols={2}>
  <Card title="Resources" icon="cubes" href="/docs/sdks/python/resources">
    The client surface.
  </Card>

  <Card title="Tiers & Limits" icon="layer-group" href="/docs/billing/tiers-and-limits">
    Rate limits behind 429s.
  </Card>

  <Card title="Troubleshooting" icon="wrench" href="/docs/troubleshooting">
    Resolve common failures.
  </Card>

  <Card title="Examples" icon="code" href="/docs/sdks/python/examples">
    End-to-end examples.
  </Card>
</CardGroup>
