# Troubleshooting

URL: https://docs.router.ezat.io/troubleshooting

> Common EZAT Router problems by symptom (wrong base URL, 401, 402, unknown model, 429 and 529, a tool ignoring your settings, cut-off streams) with the cause and the fix.

## When to use this page

Use this page when a request or a tool fails. Find the status code or symptom below; each entry gives the cause and the fix. [Errors](https://docs.router.ezat.io/reference/errors.md) lists every error type in full.

Two quick checks narrow most problems down:

- **Did the request reach EZAT Router?** Every Messages or Chat Completions request made with a valid key appears on the dashboard's **Usage** page within a few seconds, including refused ones (status **Rejected**). If nothing appears, the tool is sending the request somewhere else, or without a valid key.
- **Which format is the error in?** An API error has an error `type`, such as `{"type":"error","error":{"type":"not_found_error",…}}` or `{"error":{"code":"model_not_found",…}}`. A body like `{"statusCode":404,"message":"…"}` means the URL path itself is wrong.

## Base URL

### 404 with `Cannot POST /v1/v1/messages`

**Cause.** The base URL ends in `/v1`. The Anthropic SDKs and Claude Code add `/v1/messages` themselves, so the path doubles.

**Fix.** Use `https://api.router.ezat.io` with nothing after it: `ANTHROPIC_BASE_URL=https://api.router.ezat.io`, `base_url="https://api.router.ezat.io"`.

### 404 from an OpenAI client or tool

The body is `{"statusCode":404,…}` with a message such as `Cannot POST /v1/chat/completions` or `Cannot POST /openai/chat/completions`, or just `Not Found`.

**Cause.** The OpenAI base URL is missing `/openai/v1`, or has only part of it. OpenAI clients add `/chat/completions` and `/models` to the base URL.

**Fix.** Use `https://api.router.ezat.io/openai/v1` exactly, for example `OpenAI(base_url="https://api.router.ezat.io/openai/v1")` or `OPENAI_BASE_URL=https://api.router.ezat.io/openai/v1`. See [OpenAI-compatible base URL](https://docs.router.ezat.io/openai/base-url.md).

## Authentication

### 401 Missing API key

The message is `Missing API key. Send it in the x-api-key or Authorization: Bearer header.`

**Cause.** No key arrived. The header is missing or misspelled, or the environment variable that should hold the key is empty in the process that sent the request. Apps started from the Dock, the Start menu or an IDE don't see variables exported in a terminal.

**Fix.** Send the key as `x-api-key` or `Authorization: Bearer`. Check that the variable is set in the same shell or app that runs the tool, without printing the key:

```bash
printf 'length %s, prefix %s\n' "${#EZAT_API_KEY}" "${EZAT_API_KEY:0:8}"
```

It should print `length 48, prefix ezat_sk_`.

### 401 Invalid API key

**Cause.** The value that arrived isn't a working EZAT Router key:

- a typo, a copy that was cut off, or quotes, spaces or a line break inside the key (spaces at the ends are ignored);
- a key from another provider, such as an Anthropic or OpenAI key;
- two keys at once. When a request has both `x-api-key` and `Authorization`, EZAT Router reads `x-api-key`. A tool with an old `ANTHROPIC_API_KEY` still set sends it as `x-api-key`, and that hides the EZAT Router key in `ANTHROPIC_AUTH_TOKEN`.

**Fix.** Check the length and prefix as above. Unset any other provider's key that the tool also reads (`unset ANTHROPIC_API_KEY`), or set it to your EZAT Router key too. If the key still fails, create a new one on the **API keys** page.

### 401 revoked or expired key

The message is `This API key has been revoked` or `This API key has expired`.

**Cause.** Someone revoked the key, or it passed the expiry date chosen when it was created.

**Fix.** Create a new key on the **API keys** page and update the tool. A key can't be reactivated.

### 403 permission error

**Cause.** One of:

- `This API key is not allowed to use …`: the key was created with **Only selected models**, and this model isn't one of them.
- `This organization is suspended. Contact support@ezat.io.`: the organization's keys are all refused.

**Fix.** For the first, use a model the key allows (`GET /v1/models` with the key lists them) or create a key for all models. For the second, email support@ezat.io.

## Balance and limits

### 402 credit balance too low

The message is `Your credit balance is too low. Add credits in the EZAT Router dashboard.` In the OpenAI format the error type is `insufficient_quota`.

**Cause.** The organization's balance is zero or below. Requests are refused until it is above zero.

**Fix.** Add credit on the **Billing** page (owners, admins and billing members can). Credit appears a few seconds after payment. If you added credit and still get `402`, check that you added it to the organization the key belongs to: the organization switcher in the top bar shows which one you are looking at. See [How billing works](https://docs.router.ezat.io/billing.md).

### 402 spend limit reached

The message is `This API key reached its daily spend limit of …` (or `monthly`, or `total`).

**Cause.** The key has a spend limit, and it has spent that much in the current period.

**Fix.** A daily or monthly limit resets at the start of the next UTC day or month. Otherwise, use a key with a higher limit, or create one. See [Spend limits](https://docs.router.ezat.io/api-keys.md).

### 429 rate limit

The error type is `rate_limit_error`, with a `retry-after` header in seconds. The message tells you which limit:

- `This API key exceeded its requests-per-minute limit` (`retry-after: 30`): the key sent more than its requests per minute.
- `Rate limited upstream. Please retry shortly.` (`retry-after: 10`): the model's capacity is rate limited right now.

**Fix.** Wait the number of seconds in `retry-after`, then retry with backoff. The Anthropic and OpenAI SDKs retry these on their own. If your own traffic hits the per-key limit, spread it over time. See [Rate limits](https://docs.router.ezat.io/reference/rate-limits.md).

### 529 overloaded (503 in the OpenAI format)

The error type is `overloaded_error` (`server_error` with code `overloaded` in the OpenAI format), with a `retry-after` header. The message may say the model `has no available capacity right now`.

**Cause.** No capacity for this model is free right now. EZAT Router has already tried the other capacity it has for the model before returning this error.

**Fix.** Retry after the `retry-after` seconds, with backoff. If it keeps happening, try another model.

## Models and requests

### 404 unknown model

In the Anthropic format: `not_found_error` with the message `model: <the name you sent>`. In the OpenAI format: code `model_not_found`.

**Cause.** The name isn't a model id or alias that EZAT Router serves to this key. Common reasons: a typo; a name from another provider or a cloud provider's own id; a model that has been retired; a model in preview, which only keys with preview access can call.

**Fix.** List the models your key can use with `GET https://api.router.ezat.io/v1/models` and send one of those ids. The [Models](https://docs.router.ezat.io/models.md) page lists the other names each model accepts. Names are not case-sensitive. In Claude Code, if a model you picked isn't served, set `ANTHROPIC_MODEL` to an id from the list.

### 400 from the model

The error type is `invalid_request_error`, and the message names a field or a value.

**Cause.** The request has something the model doesn't accept. EZAT Router checks only `model`, `max_tokens` and `messages`, and passes everything else to the model as you sent it, so the model's own checks apply: for example a sampling parameter (`temperature`, `top_p`, `top_k`) that the model doesn't take, or an `anthropic-beta` feature it doesn't serve. Message Batches, the Files API, Anthropic-run server tools (web search, code execution) and the MCP connector aren't available.

**Fix.** Remove the field the message names. If Claude Code gets `400` errors naming unknown fields or beta features, set `CLAUDE_CODE_DISABLE_EXPERIMENTAL_BETAS=1` in its environment. On the OpenAI-compatible API, a few OpenAI fields are refused on purpose (for example `n` above 1, `logprobs`, `logit_bias`, audio and the legacy `functions`): see [Chat Completions](https://docs.router.ezat.io/openai/chat-completions.md).

### 413 request too large

The error type is `request_too_large`.

**Cause.** The request body is larger than 32 MB.

**Fix.** Send smaller images or documents, or fewer of them per request.

## Tools and settings

### A tool still uses its own key or base URL

Symptoms: requests don't appear on the **Usage** page, the tool reports another provider's errors, or you get `401` although the key is right.

**Cause.** The tool reads its settings from somewhere that wins over the value you set:

- **Claude Code** uses the `env` block of its settings files over variables exported in your shell. A saved claude.ai login, or an `ANTHROPIC_API_KEY` you haven't approved, can also be in play.
- **SDK code** that passes a base URL or key in the constructor ignores the environment variables (`ANTHROPIC_BASE_URL`, `ANTHROPIC_API_KEY`, `OPENAI_BASE_URL`, `OPENAI_API_KEY`).
- **Apps started outside your terminal** (editors, desktop apps) don't see your shell exports.
- **Two keys at once:** see [401 Invalid API key](#401-invalid-api-key).

**Fix.**

- In Claude Code, run `/status`. The `Anthropic base URL` line should show `https://api.router.ezat.io`, and an `Auth token` or `API key` line should name the variable that holds your EZAT Router key. If the base URL line is missing, the variable didn't reach Claude Code. Check `~/.claude/settings.json`, the project's `.claude/settings.json` and `.claude/settings.local.json` for `env` values that override yours. If Claude Code warns about two credentials, run `/logout` to drop the saved login. See [Claude Code](https://docs.router.ezat.io/tools/claude-code.md).
- In your code, pass `base_url` and the key explicitly, or remove the explicit values so the environment variables apply.
- For editors and desktop apps, set the values in the app's own settings.

### Streaming stops early

**Cause.** One of:

- **The model failed mid-stream.** Once output has started, EZAT Router can't switch to other capacity, so the stream ends with an error event: `event: error` in the Anthropic format, or a `data:` chunk with an `error` object in the OpenAI format. A request that fails like this isn't charged.
- **Your client or a proxy closed the connection.** EZAT Router stops the model. You are charged for the input and for the output generated so far, which is estimated when the stream ended before the final count: the **Usage** page marks such requests as estimated, with the status **Cancelled**.
- **A read timeout in your client** is shorter than the gap between events. EZAT Router sends a keep-alive (an `event: ping` in the Anthropic format, an SSE comment in the OpenAI format) after 15 seconds without output.

**Fix.** Retry a request that ended with an error event. Make sure your client's read timeout is well above 15 seconds and that no proxy buffers or cuts long responses.

### 504 on a long request

The error type is `timeout_error`, with the message `The model took longer than 590 seconds. Send long requests with "stream": true.`

**Cause.** A request without streaming gets no response until the model finishes, and EZAT Router ends it after 590 seconds.

**Fix.** Send long requests with `"stream": true` (or the SDK's streaming call).

## Contacting support

If you can't fix a problem, email support@ezat.io with:

- the `request-id` header of the response, or the `x-request-id` header if there is no `request-id` (Anthropic-format error bodies carry the same value as `request_id`);
- the time of the request (with time zone), the endpoint, the status code and the error message;
- your **Organization ID** from **Settings**, for billing questions.

Never send your API key: support never needs it.

## For AI agents

1. Read the status code and the error `type` before changing anything. Don't retry `400`, `401`, `402`, `403`, `404` or `413`.
2. For `429`, `500` and `529` (`503` in the OpenAI format), wait at least the `retry-after` seconds and retry with backoff.
3. A `404` with a `statusCode` field means the URL path is wrong: use `https://api.router.ezat.io` for Anthropic-format clients and `https://api.router.ezat.io/openai/v1` for OpenAI-format clients.
4. To check the key, print only its length and first 8 characters, then call `GET https://api.router.ezat.io/v1/models`.
5. When asking the user for help, give them the `request-id` (or `x-request-id`) and the error message, never the key.