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

# Errors & Rate Limits

> Status codes Declaw returns when a platform limit is hit, the JSON shape of each error, and how clients should handle them.

Unless noted otherwise, every platform-level rejection comes back with an HTTP status code and a JSON body of shape `{"message": "<reason>"}`. This page lists the ones that depend on your account state (balance, tier, rate) or protocol rather than request validity. Request-validity errors (`400`, `404`, `410`, `502`, `503`) are documented inline on each API reference page.

## 464 Unsupported protocol version

Returned by the load balancer when a client connects using HTTP/1.1. Declaw Cloud requires HTTP/2.

This error has **no JSON body** — it is a raw status code from the load balancer, not from the Declaw API server.

**Common causes:**

* Python `requests` library (does not support HTTP/2 — use the [Declaw Python SDK](/sdks/python/overview) or `httpx` with `http2=True`)
* `curl` without the `--http2` flag
* Older HTTP libraries that default to HTTP/1.1

**Recommended handling:** switch to an official Declaw SDK, or ensure your HTTP client negotiates HTTP/2 via ALPN.

## 402 Insufficient balance

Returned on any billable endpoint when `sandbox_free_micros + balance_micros ≤ 0` (for sandbox operations) or `guardrails_free_micros + balance_micros ≤ 0` (for guardrails operations).

```json theme={null}
{ "message": "insufficient balance" }
```

Triggered on: `POST /sandboxes`, command endpoints, filesystem endpoints, and guardrails-scanning paths for Pro and Enterprise accounts. Free accounts hit `402` only after their free credits are fully drained.

**Recommended handling:** surface to the user as "top up required", then retry after a deposit lands. Deposits are processed synchronously — a successful `POST /accounts/{id}/deposits` immediately updates `balance_micros`.

## 403 Tier limit exceeded

Returned when a create request asks for resources above your tier cap. The request body is rejected before the sandbox is provisioned.

```json theme={null}
{ "message": "vcpu limit exceeds tier allowance" }
{ "message": "memory limit exceeds tier allowance" }
{ "message": "disk limit exceeds tier allowance" }
{ "message": "session duration exceeds tier limit" }
```

Also returned on:

* `{"message": "unknown tier: <name>"}` — the account's tier doesn't map to a known config (administrative error, contact support)
* `{"message": "forbidden: cannot access another account"}` — calling an `/accounts/{id}` endpoint with a different owner\_id

**Recommended handling:** cap your request parameters to the numbers in [Plans & Limits](/platform/plans). Tier upgrades are handled via your dashboard (Pro) or [sales](mailto:team@declaw.ai) (Enterprise).

## 429 Too many requests

Returned in two different scenarios. Both have the same status code but different meanings.

### Concurrent sandbox cap

```json theme={null}
{ "message": "concurrent sandbox limit reached for tier: pro" }
```

Your account has `MaxConcurrent` sandboxes in the `running` state. Kill or let a sandbox time out before creating another.

### Request rate limit

```json theme={null}
{ "message": "rate limit exceeded" }
{ "message": "sandbox creation rate limit exceeded" }
```

You've exceeded the per-second request budget for your tier. The rate limiter uses a **1-second sliding window** — wait one second and retry.

### Fixed-bucket rate limits

A handful of sensitive endpoints have lower, fixed budgets that apply regardless of tier:

| Bucket         | Scope         | Limit           |
| -------------- | ------------- | --------------- |
| Deposit        | per account   | 10 / hour       |
| Tier change    | per account   | 5 / day         |
| Account create | per client IP | 5 / hour        |
| Login          | per client IP | 10 / 15 minutes |

Exceeding any of these returns a descriptive `{"message": "too many ... requests, try again later"}` response.

### Response headers

General and create rate-limit rejections include per-bucket accounting headers:

```
X-RateLimit-Limit-general: 2000
X-RateLimit-Remaining-general: 0
```

<Note>
  Declaw does not currently emit a `Retry-After` header. Clients should use a fixed 1-second backoff for general/create rate-limit errors, and progressive backoff (e.g. 30s, 60s, 120s) for fixed-bucket errors.
</Note>

## Recommended client-side handling

A production client should distinguish these three cases:

```python theme={null}
from declaw import Sandbox, InsufficientBalanceException, RateLimitException

try:
    sbx = Sandbox.create(template="python")
except InsufficientBalanceException as e:
    # 402 — out of money. Surface to operator, do not retry.
    alert_ops(f"Wallet empty ({e.wallet_type}). Top up required.")
    raise
except RateLimitException as e:
    # 429 — transient. Retry after a short wait.
    time.sleep(e.retry_after or 1)
    sbx = Sandbox.create(template="python")
```

The SDK maps each HTTP status to a typed exception — see [Python error handling](/sdks/python/error-handling) or [TypeScript error handling](/sdks/typescript/error-handling) for the full class list.

## Checklist

* **Always** handle `429` with a retry — it's transient by definition
* **Never** retry `402` without topping up — you'll just burn quota against the same empty wallet
* **Never** retry `403` without changing the request — the tier cap won't move on its own
* Cache tier limits from [Plans & Limits](/platform/plans) client-side; clamp request parameters before sending
* Alert on unexpected `402` as early as possible — your account is locked out of billable operations until a deposit succeeds
