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

# Error Codes

> API error reference: HTTP status codes, error_code values, and retry classification.

## Response shape

`/v1/*` (OpenAI-compatible):

```json theme={null}
{ "error": { "type": "invalid_request_error", "message": "...", "code": 400 } }
```

Dashboard / internal:

```json theme={null}
{ "code": 401, "message": "..." }
```

## HTTP status codes

| Code  | Name                 | Meaning                                           |
| ----- | -------------------- | ------------------------------------------------- |
| `200` | OK                   |                                                   |
| `400` | Bad Request          | Invalid parameters or generation still processing |
| `401` | Unauthorized         | API key missing or invalid                        |
| `402` | Insufficient Credits | Balance too low                                   |
| `404` | Not Found            | Unknown endpoint or resource                      |
| `422` | Validation Error     | Body failed schema validation                     |
| `429` | Rate Limited         | Backoff and retry                                 |
| `455` | Service Unavailable  | Maintenance or upstream outage                    |
| `500` | Server Error         | Internal error                                    |
| `501` | Generation Failed    | Model accepted but produced no output             |
| `505` | Feature Disabled     | Endpoint disabled                                 |

## `error_code` values

A stable, finer-grained category set on every failed generation. Read from `GET /logs` (per-row `error_code` field). Naming matches OpenAI's `error.code` convention.

| `error_code`               | HTTP     | Retry? | Fix                                                  |
| -------------------------- | -------- | ------ | ---------------------------------------------------- |
| `insufficient_quota`       | 402, 455 | No     | Top up at [/billing](https://routerbase.com/billing) |
| `content_policy_violation` | 400      | No     | Reword the prompt or change the input image          |
| `rate_limit_exceeded`      | 429      | Yes    | Exponential backoff                                  |
| `timeout`                  | 455      | Yes    | Resubmit; upstream may have completed                |
| `provider_unavailable`     | 455      | Yes    | Transient — retry shortly                            |
| `invalid_request_error`    | 400      | No     | Fix the parameters                                   |
| `server_error`             | 500      | Yes    | Retry; contact support if persistent                 |
| `internal_error`           | 500      | Yes    | Retry; report if reproducible                        |

## Retry classification

```python theme={null}
RETRYABLE_CODES = {
    "rate_limit_exceeded",
    "timeout",
    "provider_unavailable",
    "server_error",
    "internal_error",
}

def should_retry(error_code: str | None, http_status: int) -> bool:
    if error_code in RETRYABLE_CODES:
        return True
    return http_status == 429 or http_status >= 500
```

## Backoff example

```python theme={null}
import time, requests

def post_with_retry(url, headers, body, max_retries=5):
    for attempt in range(max_retries):
        res = requests.post(url, headers=headers, json=body)
        if res.status_code < 429 or (res.status_code != 429 and res.status_code < 500):
            return res
        time.sleep(2 ** attempt)
    raise RuntimeError("max retries exceeded")
```
