# Errors

> What each HTTP status code and error message from the API means, how to fix 401, 403, 404 and 429 errors, low balance and unknown models, and when to retry.

Source: https://oneaiapikey.com/docs/errors

Errors come back as normal HTTP status codes with a JSON body that says what went wrong. Most problems are one of three things: the key, the base URL, or the balance. This page helps you tell them apart quickly.

## Error format

Errors use the OpenAI-style `error` envelope, which every OpenAI SDK already understands. Errors that come from the model provider keep the provider's status code and message.

401 invalid key:

```json
{
  "error": {
    "code": "",
    "message": "Invalid token (request id: 20261008101503123456789abcdef)",
    "type": "api_error"
  }
}
```

403 balance:

```json
{
  "error": {
    "code": "insufficient_user_quota",
    "message": "Your balance is too low for this request. Add credit under Billing in the console. (request id: 20261008101503123456789abcdef)",
    "type": "api_error"
  }
}
```

503 model unavailable:

```json
{
  "error": {
    "code": "model_not_found",
    "message": "No available channel for model claude-sonnet-5-5 under group default (distributor) (request id: 20261008101503123456789abcdef)",
    "type": "api_error"
  }
}
```

404 wrong path:

```json
{
  "error": {
    "message": "Unknown endpoint. The API lives under /v1 (for example POST /v1/chat/completions).",
    "type": "invalid_request_error",
    "param": null,
    "code": "not_found"
  }
}
```

Branch on the HTTP status first, then on `error.code` where it is set (for example `model_not_found` or `insufficient_user_quota`). Match on the code, not on the message text: messages are written for people and can change. Log `error.message` anyway, since it names the model, group or limit involved.

### On /v1/messages

Once a request on the Anthropic endpoint reaches the model step, errors use Anthropic's shape. Checks that run before that (key, model allowlist, IP allowlist, model availability) answer with the OpenAI envelope above on every endpoint. The Anthropic SDKs raise an error from the HTTP status either way.

Anthropic-format error:

```json
{
  "type": "error",
  "error": {
    "type": "api_error",
    "message": "Your balance is too low for this request. Add credit under Billing in the console. (request id: 20261008101503123456789abcdef)"
  }
}
```

### Request id

Every response has an `X-Request-Id` header, and gateway error messages end with `(request id: …)`. Log it with failures; it is the fastest way for support to find your request.

## Status codes

Fix the request, do not retry Safe to retry with backoff

- 400Bad Request

  Bad RequestFix, do not retry

  Cause: Invalid JSON, a missing or invalid field, a prompt longer than the context window, or a model that is listed but not priced yet (model_price_error).

  Fix: Read the message, fix the body, shorten the input. [Details](https://oneaiapikey.com/docs/errors#bad-request)
- 401Unauthorized

  UnauthorizedFix, do not retry

  Cause: Key missing, mistyped, disabled, expired or deleted, or sent in a header the endpoint does not read.

  Fix: Check the header and that the environment variable is loaded. Create a new key if needed. [Details](https://oneaiapikey.com/docs/errors#invalid-key)
- 403Forbidden

  ForbiddenFix, do not retry

  Cause: Balance, plan allowance or the key spending limit is used up; the key may not use this model or group; or the request came from an IP the key does not allow.

  Fix: Add credit, raise the key limit, or edit the key settings. [Details](https://oneaiapikey.com/docs/errors#insufficient-balance)
- 404Not Found

  Not FoundFix, do not retry

  Cause: Wrong URL path, usually /v1 missing (OpenAI format) or doubled (Anthropic format).

  Fix: Use the base URLs exactly as shown in the docs. [Details](https://oneaiapikey.com/docs/errors#error-format)
- 413Payload Too Large

  Payload Too LargeFix, do not retry

  Cause: The request body is over 128 MB, usually from large base64 images or files.

  Fix: Shrink or split the input. [Details](https://oneaiapikey.com/docs/errors#bad-request)
- 429Too Many Requests

  Too Many RequestsRetry with backoff

  Cause: The model provider is throttling, or a per-model rate limit is in force.

  Fix: Back off and retry. Reduce parallel requests. [Details](https://oneaiapikey.com/docs/errors#rate-limited)
- 500Internal Server Error

  Internal Server ErrorRetry with backoff

  Cause: Unexpected error in the gateway or at the provider.

  Fix: Retry with backoff. Report it with the request id if it persists. [Details](https://oneaiapikey.com/docs/errors#upstream-errors)
- 501Not Implemented

  Not ImplementedFix, do not retry

  Cause: An OpenAI endpoint the gateway does not offer, such as Files, fine-tuning or image variations.

  Fix: Use a supported endpoint (see the API reference). [Details](https://oneaiapikey.com/docs/errors#not-implemented)
- 502Bad Gateway

  Bad GatewayRetry with backoff

  Cause: The provider returned an invalid response or dropped the connection.

  Fix: Retry with backoff. [Details](https://oneaiapikey.com/docs/errors#upstream-errors)
- 503Service Unavailable

  Service UnavailableRetry with backoff

  Cause: No provider route is available for the model right now, the model is not enabled for your account, or the provider is overloaded.

  Fix: Check the model id; retry later or switch to a sibling model. [Details](https://oneaiapikey.com/docs/errors#model-not-found)

## Invalid or missing key

Every key problem returns `401` with the message `Invalid token`, whatever the exact cause, so check each of these:

- Print the variable in the same terminal (`echo $RELAYKIT_API_KEY`, or `$env:RELAYKIT_API_KEY` in PowerShell). An empty value is the most common cause.
- Make sure the value starts with `sk-` and has no quotes, spaces or line breaks copied along with it.
- OpenAI clients send `Authorization: Bearer`; Anthropic clients send `x-api-key`. `x-api-key` is read only on `/v1/messages` and `/v1/models`; everywhere else use the Bearer header.
- Check under [API keys](https://oneaiapikey.com/console/keys) that the key is enabled, not past its expiry date, and not deleted.

## Insufficient balance

When the request cannot be paid for, the gateway rejects it before calling the model, with `403`. Nothing is charged. The `code` tells you which limit was hit:

- `insufficient_user_quota`: the account balance (or the plan allowance, if billing uses a plan only) is too low. Add credit under [Billing](https://oneaiapikey.com/console/billing).
- `pre_consume_token_quota_failed`: this key's own spending limit is reached, even though the account may have money. Raise or remove the limit under [API keys](https://oneaiapikey.com/console/keys).

Before a request runs, the gateway reserves an estimate of its cost, so a request can be refused while the balance is still slightly above zero. A lower `max_tokens` lowers the reservation. New balance applies to the next request immediately.

> **Avoid surprises:** Give each app or teammate its own key with a spending limit. A runaway agent loop then stops at the limit instead of draining your whole balance. See [Cost control](https://oneaiapikey.com/docs/cost-control).

## Access denied (other 403s)

All 403 messages you can get from the gateway, and what each one means:

| Message | `code` | Meaning |
| --- | --- | --- |
| Your balance is too low for this request. Add credit under Billing in the console. | insufficient_user_quota | Your account balance cannot cover the request. |
| Your plan allowance is used up or no plan is active. Add balance, or wait for the allowance to reset. | insufficient_user_quota | Billing is set to use a plan only, and the plan allowance is spent. |
| token quota is not enough, token remain quota: …, need quota: … | pre_consume_token_quota_failed | This key reached the spending limit you set on it. The account balance is not the problem. |
| This token has no access to model … | (empty) | The key has a model allowlist and this model is not on it. |
| This key or account cannot use the … group | (empty) | The key is pinned to a group your account cannot use, often after a plan change. |
| The … group is no longer available | (empty) | The key is pinned to a group that was retired. |
| Your IP address is not on this key's allowed list | access_denied | The key has an IP allowlist and the request came from another address. Check the key’s Allowed IP addresses on the keys page, or clear the field to accept any address. |

Spend limit, expiry and model list are on the key's edit dialog under [API keys](https://oneaiapikey.com/console/keys). See [Authentication and keys](https://oneaiapikey.com/docs/authentication).

## Model not found

If the gateway cannot route the `model` you sent, it answers `503` with code `model_not_found` and a message that names the model, or with "Model … is not available right now. Try again shortly or pick another model." Some clients show this as "model not found" or 404.

- Copy ids exactly from `GET /v1/models` or the [models table](https://oneaiapikey.com/docs/models#current-models). Ids are case-sensitive: `claude-sonnet-5-5`, not a display name.
- New accounts start at $0 and see no models until the account has paid $3 or more in total; until then every model returns this error. Add credit under [Billing](https://oneaiapikey.com/console/billing).
- Calling an OpenAI-only model on `/v1/messages`? Use the OpenAI endpoint instead (see [models by format](https://oneaiapikey.com/docs/api-reference#model-formats)).

## Bad request and context length

A `400` means the request itself needs changing, so retrying it unchanged will fail again. Typical messages mention an invalid parameter, a missing `model`, an image the model cannot read, or a prompt that exceeds the context window. For long conversations, trim or summarise old turns, and keep `max_tokens` within the model's output limit.

- `model_price_error` ("Model … has not been priced by the administrator yet"): the model is listed but not open for use yet. Pick another model, or [tell us](mailto:support@relaykit.dev) which one you need.
- `413`: the body is larger than 128 MB, almost always because of inline images or files. Resize them or send fewer per request.

## Not implemented (501)

Some OpenAI endpoints are not offered: Files (`/v1/files`), fine-tuning, image variations, deleting models, and `/v1/messages/count_tokens`. They return `501` with code `api_not_implemented` (or `404`). The [API reference](https://oneaiapikey.com/docs/api-reference#endpoints) lists what is available.

## Rate limited (429)

`429` means slow down, not stop. Today it almost always comes from the model provider during peak load; the gateway does not apply its own per-account request limit on the API. If a per-model limit is switched on, its message says so: "Rate limit reached: at most N requests per M minutes". Retry with exponential backoff, honour a `Retry-After` header when present, and cap how many requests you run in parallel. See [Rate limits and retries](https://oneaiapikey.com/docs/rate-limits).

## Upstream errors (5xx)

`500`, `502` and `503` are usually short-lived: a provider hiccup or a capacity spike for one model. Retry with backoff. The gateway does not retry for you, so a failed attempt reaches your code as it happened. If one model keeps failing, switch to a sibling model temporarily; the rest of your code does not change because every model shares the same API.

## Timeouts

- **Streaming**: the gateway closes a stream when the provider sends nothing for 300 seconds. Reasoning models with long thinking phases are the usual cause.
- **Non-streaming**: the gateway does not cut the request off, but your HTTP client and any proxy on the way may. A long answer with nothing sent until the end is the most likely to time out.
- Use `stream: true` for long outputs: tokens flow continuously, so nothing sits idle. Set your client's read timeout to a few minutes.
- Do not blindly retry a timed-out request: the model may have finished and been billed even though your client never saw the answer. If you disconnect early, you pay for the tokens produced up to that point.

## Retries with backoff

Retry only on `429`, `500`, `502`, `503` and network errors. Wait longer after each attempt (1s, 2s, 4s… with random jitter) and give up after about five tries. Never retry `400`, `401`, `403`, `404` or `501`: they will fail the same way.

Python:

```python
import os, random, time
from openai import OpenAI, APIStatusError, APIConnectionError

client = OpenAI(
    base_url="https://api.oneaiapikey.com/v1",
    api_key=os.environ["RELAYKIT_API_KEY"],
    max_retries=0,  # we handle retries ourselves below
)

RETRYABLE = {429, 500, 502, 503}

def backoff(attempt, retry_after=None):
    if retry_after and retry_after.isdigit():
        return int(retry_after)               # honour the server's hint
    return min(30, 2 ** attempt) + random.random()  # 1s, 2s, 4s… + jitter

def chat(attempts=5, **kwargs):
    for attempt in range(attempts):
        try:
            return client.chat.completions.create(**kwargs)
        except APIStatusError as e:
            if e.status_code not in RETRYABLE or attempt == attempts - 1:
                raise
            time.sleep(backoff(attempt, e.response.headers.get("retry-after")))
        except APIConnectionError:
            if attempt == attempts - 1:
                raise
            time.sleep(backoff(attempt))

reply = chat(model="gpt-5.6-terra", messages=[{"role": "user", "content": "ping"}])
```

Node:

```js
const RETRYABLE = new Set([429, 500, 502, 503]);
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
const backoff = (i) => Math.min(30_000, 1000 * 2 ** i) + Math.random() * 1000;

export async function chat(body, attempts = 5) {
  for (let i = 0; i < attempts; i++) {
    let res;
    try {
      res = await fetch("https://api.oneaiapikey.com/v1/chat/completions", {
        method: "POST",
        headers: {
          Authorization: `Bearer ${process.env.RELAYKIT_API_KEY}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify(body),
      });
    } catch (err) {
      if (i === attempts - 1) throw err; // network error
      await sleep(backoff(i));
      continue;
    }
    if (res.ok) return res.json();
    if (!RETRYABLE.has(res.status) || i === attempts - 1) {
      throw new Error(`${res.status} ${res.headers.get("x-request-id")}: ${await res.text()}`);
    }
    const hint = Number(res.headers.get("retry-after"));
    await sleep(hint > 0 ? hint * 1000 : backoff(i));
  }
}
```

> **SDKs already retry:** The official OpenAI and Anthropic SDKs retry connection errors, `429` and `5xx` a couple of times by default. Tune it with `max_retries` (Python) or `maxRetries` (Node) instead of wrapping your own loop around theirs.

## Getting help

If an error persists, email [support@relaykit.dev](mailto:support@relaykit.dev) with:

- the request id (from the `X-Request-Id` header or the end of the error message);
- the time of the request (with timezone), the endpoint and the model id;
- the HTTP status and the full error message;
- the key's name or its last four characters. **Never send the full key.**

Minimal reproduction to include:

```bash
curl -i https://api.oneaiapikey.com/v1/chat/completions \
  -H "Authorization: Bearer $RELAYKIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "claude-haiku-4-5", "messages": [{"role": "user", "content": "ping"}]}'
```
