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

# Error Handling

> Understand the API error format and handle errors gracefully.

## Error response format

Errors return a JSON body with an `error` object and an appropriate HTTP status:

```json theme={null}
{
  "error": {
    "message": "Invalid API key provided",
    "type": "authentication_error",
    "code": null,
    "param": null
  }
}
```

The `type` field is the machine-readable discriminator. Common values:

| `type`                  | When                                              |
| ----------------------- | ------------------------------------------------- |
| `authentication_error`  | Missing or invalid API key (401).                 |
| `invalid_request_error` | Malformed body or an unsupported parameter (400). |
| `model_not_found`       | The `model` id is not available (400).            |
| `upstream_error`        | The upstream provider is unavailable (502).       |

## Status codes

| Status | Meaning                                           |
| ------ | ------------------------------------------------- |
| 400    | Bad request (invalid parameters or unknown model) |
| 401    | Unauthorized (missing or invalid API key)         |
| 403    | Forbidden (for example, insufficient credits)     |
| 429    | Rate limit exceeded                               |
| 500    | Server error                                      |
| 502    | Upstream provider unavailable                     |
| 503    | Service temporarily unavailable                   |

## Handle errors with the SDK

OpenAI client libraries map these statuses to typed exceptions:

```python Python theme={null}
import os, time
from openai import OpenAI, AuthenticationError, RateLimitError, APIError

client = OpenAI(base_url="https://api.redpill.ai/v1", api_key=os.environ["API_KEY"])

try:
    resp = client.chat.completions.create(
        model="openai/gpt-5",
        messages=[{"role": "user", "content": "Hello"}],
    )
except AuthenticationError:
    print("Invalid API key")
except RateLimitError:
    print("Rate limited; back off and retry")
except APIError as e:
    print(f"API error {e.status_code}: {e.message}")
```

```javascript JavaScript theme={null}
try {
  const resp = await client.chat.completions.create({
    model: "openai/gpt-5",
    messages: [{ role: "user", content: "Hello" }],
  });
} catch (error) {
  if (error.status === 401) console.error("Invalid API key");
  else if (error.status === 429) console.error("Rate limited");
  else console.error("API error:", error.message);
}
```

## Retry transient errors

Retry `429` and `5xx` responses with exponential backoff. Do not retry `400` or `401`: they will
fail again until you fix the request or the key.

```python theme={null}
import time
from openai import RateLimitError, APIError

def with_retry(call, max_retries=3):
    for attempt in range(max_retries):
        try:
            return call()
        except (RateLimitError, APIError) as e:
            status = getattr(e, "status_code", 500)
            if status in (429, 500, 502, 503) and attempt < max_retries - 1:
                time.sleep(2 ** attempt)
            else:
                raise
```

## Common cases

<AccordionGroup>
  <Accordion title="Invalid API key (401, authentication_error)">
    Check the key in the [dashboard](https://www.redpill.ai/dashboard), confirm the `Bearer ` prefix,
    and check for stray whitespace.
  </Accordion>

  <Accordion title="Unknown model (400, model_not_found)">
    The `model` id is not available. List valid ids with [`GET /v1/models`](/api-reference/models).
    Note that model ids are prefixed, for example `openai/gpt-5`.
  </Accordion>

  <Accordion title="Unsupported parameter (400, invalid_request_error)">
    Some models reject a parameter. For example, newer OpenAI models (GPT-5, o3, o4) require
    `max_completion_tokens` instead of `max_tokens`. Check the model's `supported_parameters` in
    `/v1/models`.
  </Accordion>

  <Accordion title="Rate limited (429)">
    Back off and retry with exponential backoff, and reduce your request rate.
  </Accordion>

  <Accordion title="Upstream unavailable (502, upstream_error)">
    The upstream provider failed to respond. Retry, or try another model.
  </Accordion>
</AccordionGroup>

## Best practices

* Branch on the HTTP status and the `error.type`, not on the message text.
* Retry only transient errors (`429`, `5xx`) with backoff.
* Keep keys in environment variables and never log them.
