> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://doc.enterpriserouter.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://doc.enterpriserouter.com/_mcp/server.

# Error Reference

All proxy errors return JSON with a single `error` field:

```json
{"error": "error message here"}
```

## Error codes

### 401 Unauthorized

| Error               | Cause                                                                                              |
| ------------------- | -------------------------------------------------------------------------------------------------- |
| `missing proxy key` | No `sk-proxy-...` value found in `Authorization: Bearer`, `x-api-key`, or `x-goog-api-key` headers |
| `invalid proxy key` | Key not found or hash doesn't match                                                                |

### 403 Forbidden

| Error                  | Cause                                       | Resolution                                                     |
| ---------------------- | ------------------------------------------- | -------------------------------------------------------------- |
| `key_revoked`          | Key has been revoked                        | Create a new key                                               |
| `key_expired`          | Key is past its expiry date                 | Create a new key or extend the expiry                          |
| `ip_blocked`           | Client IP not in the key's allowlist        | Add the IP to the key's allowed IPs, or remove IP restrictions |
| `provider_not_allowed` | Provider not in the key's allowed providers | Update the key's provider list                                 |
| `model_not_allowed`    | Model not in the key's allowed models       | Update the key's model list                                    |
| `spend_exceeded`       | Key has reached its spend limit             | Increase the limit or wait for the reset period                |
| `insufficient_credits` | Organization has no remaining credits       | Purchase more credits in Settings > Billing                    |
| `budget_exceeded`      | Organization budget config limit reached    | Increase the budget or wait for the period to reset            |

### 429 Too Many Requests

| Error                       | Cause                                   | Resolution                                          |
| --------------------------- | --------------------------------------- | --------------------------------------------------- |
| `rate_limited`              | Key has exceeded its RPM limit          | Reduce request rate or increase the key's RPM limit |
| `organization_rate_limited` | Organization has exceeded its RPM limit | Reduce request rate or increase the org RPM limit   |

Check the `X-RateLimit-Remaining` and `X-RateLimit-Reset` response headers to manage your request rate.

### 400 Bad Request

| Error                                  | Cause                                                                |
| -------------------------------------- | -------------------------------------------------------------------- |
| `unknown provider`                     | URL path doesn't start with `/openai/`, `/anthropic/`, or `/gemini/` |
| `provider not configured`              | Provider exists but has no API key configured on the server          |
| `invalid request body`                 | JSON parsing failed                                                  |
| `model must use provider/model format` | Unified mode: model name couldn't be resolved to a provider          |

### 502 Bad Gateway

| Error                     | Cause                                                   |
| ------------------------- | ------------------------------------------------------- |
| `upstream request failed` | The provider didn't respond (connection error, timeout) |

For non-streaming requests, the gateway retries with exponential backoff (up to 2 retries, 250ms–4s). A 502 means all attempts failed. Streaming requests are not retried because partial data may have already been sent to the client.

### 503 Service Unavailable

| Error                              | Cause                                                           |
| ---------------------------------- | --------------------------------------------------------------- |
| `provider temporarily unavailable` | The provider's circuit breaker is open due to repeated failures |
| `service_unavailable`              | Internal error (e.g., Redis rate limiter unreachable)           |

Each provider has a circuit breaker that opens after 10 failures or a 50%+ failure rate over 20+ requests within a 60-second window. Once open, all requests to that provider are rejected for a 30-second cooldown. After the cooldown, a single probe request is allowed through — if it succeeds, the circuit closes and traffic resumes normally.

## Rate limit headers

On rate-limited responses, these headers are included:

```
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1712345678
```

## Budget warning header

When your organization is approaching its budget limit but requests are still allowed:

```
X-Budget-Warning: approaching_limit
```