# Коды ошибок

Единый формат для всех ошибок, что означает каждый код и что делать, если вы его получили.

> https://nezhagate.com/ru/docs/guide/errors

## Формат ошибок

При ошибке эндпоинт `/v1` возвращает статус 4xx / 5xx и JSON, как в примере ниже: `message` — текст для человека, `type` — общий класс ошибки, `code` — стабильный машиночитаемый идентификатор, а `param` называет поле, в котором ошибка (`null`, если такого поля нет). Ориентируйтесь на HTTP-статус и `code`, а не на текст `message`: он может быть на английском, на китайском или на обоих языках сразу, и его формулировки меняются.

```
{
  "error": {
    "message": "Insufficient balance — please top up",
    "type": "insufficient_quota",
    "code": "insufficient_quota",
    "param": null
  }
}
```

Эндпоинты `/anthropic` используют собственный формат Anthropic, без `code` и `param`; ориентируйтесь на HTTP-статус и `error.type`:

```
{
  "type": "error",
  "error": {
    "type": "not_found_error",
    "message": "model: gpt-5.5"
  }
}
```

- Некоторые ошибки содержат дополнительные поля верхнего уровня, например `attempts`, когда заняты все линии, или `retry_after`, когда свободной линии временно нет. Незнакомые поля просто игнорируйте.

- Если поставщик модели отклоняет запрос (например, из-за слишком длинного контекста), в `message` — формулировка самого поставщика, а в `code` — его значение или `invalid_request`, если он его не передал.

## HTTP-статусы: краткая сводка

| HTTP | Когда возникает |
| --- | --- |
| **400** | Неверный параметр или неизвестная модель (например, `model_not_found`); `error.param` указывает на поле. |
| **401** | Нет ключа, или он недействителен либо отключён (`missing_api_key`, `invalid_api_key`). |
| **402** | Недостаточно средств или ключ исчерпал свой бюджет (`insufficient_quota`). |
| **403** | Модели нет в списке разрешённых моделей ключа, или запрос пришёл не с разрешённого для ключа IP (`permission_denied`). |
| **404** | Пути не существует, либо id задачи неизвестен, старше 3 дней хранения записи или задачу отправил другой аккаунт (`job_not_found`). |
| **429** | Превышен лимит запросов в минуту для этого ключа или дневная квота бесплатной модели, либо заняты все линии модели (`rate_limit_exceeded`). Подождите столько секунд, сколько указано в `Retry-After`, а если его нет — несколько секунд, и повторите. |
| **502** | Ошибка или таймаут на стороне поставщика, и переключение линий не помогло; причина в `code`, например `upstream_timeout` или `upstream_unavailable`. Запрос не оплачивается, его можно повторить. |
| **503** | Модель на обслуживании (`model_maintenance`) или на нашей стороне произошёл кратковременный сбой (`service_unavailable`). Запрос не оплачивается; повторите позже. |

## Все коды ошибок

Ошибки, которые возвращает шлюз, по категориям. Одному HTTP-статусу может соответствовать несколько кодов, поэтому ориентируйтесь на `code`.

### Авторизация и аккаунт

| HTTP | code | Причина | Что делать |
| --- | --- | --- | --- |
| **401** | `missing_api_key` | Нет заголовка `Authorization: Bearer`. Эндпоинты `/v1` не читают `x-api-key`. | Добавьте `Authorization: Bearer YOUR_API_KEY`. |
| **401** | `invalid_api_key` | Ключ не существует, удалён или отключён, либо отключён аккаунт. | Проверьте ключ на странице API Keys в консоли. |
| **402** | `insufficient_quota` | Баланс аккаунта исчерпан (опустился ниже порога овердрафта). | Пополните баланс и повторите. |
| **403** | `permission_denied` | Запрос пришёл с IP, которого нет в списке разрешённых IP ключа. | Отправляйте запросы с разрешённого IP или измените список в консоли. |

### Лимиты, заданные для ключа

| HTTP | code | Причина | Что делать |
| --- | --- | --- | --- |
| **429** | `rate_limit_exceeded` | Превышен лимит запросов в минуту, заданный для этого ключа (считается за последние 60 секунд). Заголовка `Retry-After` нет. | Подождите несколько секунд и повторите или увеличьте лимит ключа в консоли. |
| **429** | `rate_limit_exceeded` | Исчерпана дневная квота бесплатной модели (на аккаунт, за сутки по UTC). В `message` может быть предложена платная модель на замену. | Продолжите после 00:00 UTC или перейдите на платную модель. |
| **402** | `insufficient_quota` | Исчерпан дневной бюджет ключа (за сутки по UTC) или его общий лимит. | Продолжите на следующий день или увеличьте лимит в консоли. |
| **403** | `permission_denied` | Модели нет в списке разрешённых моделей ключа. | Используйте модель из списка разрешённых или измените список в консоли. |

### Сам запрос

| HTTP | code | Причина | Что делать |
| --- | --- | --- | --- |
| **400** | `invalid_json` / `invalid_encoding` | Тело запроса — невалидный JSON; если оно не в UTF-8 — `invalid_encoding`. | Проверьте синтаксис JSON и кодировку. |
| **400** | `invalid_request` | Недопустимый параметр: тело запроса — не JSON-объект, `n` — не целое число, не удаётся прочитать референсное изображение или видео (в `message` указано, какое и почему), в `/v1/images/edits` нет референсного изображения, длительность / разрешение / пропорция / число референсов видео выходят за пределы, допустимые для модели, и т. п. | Исправьте то, что указано в `message`, и отправьте снова. |
| **400** | `invalid_messages` / `invalid_role` / `invalid_max_tokens` | В запросе к чату поле `messages` отсутствует, пустое или имеет неверный формат, у `role` недопустимое значение либо `max_tokens` — не положительное целое число. Поле указано в `param`. | Исправьте поле, указанное в `param`. |
| **400** | `missing_prompt` | В запросе к `/v1/images/generations` нет `prompt`. | Добавьте `prompt`. |
| **400** | `unsupported_resolution` | Модель не поддерживает выбранный уровень разрешения (например, у генерации изображений Grok нет 4K). | Выберите другой уровень; доступные уровни указаны в документации каждой модели. |
| **400** | `invalid_callback_url` | `callback_url` — не публичный адрес http(s) или длиннее 2000 символов. | Укажите адрес, доступный из интернета. |
| **400** | `max_tokens_too_small` | Модель с размышлениями потратила весь `max_tokens` на размышления и не написала ответ (непотоковый чат). | Увеличьте `max_tokens` и повторите. |
| **404** | `not_found` | Такого пути эндпоинта не существует. | Проверьте путь; все эндпоинты перечислены в [справочнике API](https://nezhagate.com/ru/docs/api). |
| **404** | `job_not_found` | ID задачи неизвестен, срок хранения записи (3 дня) истёк или задачу отправил другой аккаунт; та же ошибка возникает, если опрашивать задачу изображения через эндпоинт видео (или наоборот). | Проверьте id задачи и эндпоинт. Ссылка на результат хранится 60 дней, и истечение срока хранения записи о задаче на неё не влияет. |

### Статус модели

| HTTP | code | Причина | Что делать |
| --- | --- | --- | --- |
| **400** | `model_not_found` | ID модели написан с ошибкой, `model` не передан или модель нельзя использовать на этом эндпоинте (например, чат-модель на эндпоинте изображений). | Берите ID модели из `GET /v1/models` или из [справочника API](https://nezhagate.com/ru/docs/api). |
| **400** | `model_disabled` | Модель снята с продажи. | Перейдите на другую модель; если у модели есть замена, её страницы перенаправляют на замену. |
| **400** | `model_coming_soon` | Модель анонсирована, но вызывать её пока нельзя. | Дождитесь объявления о запуске. |
| **503** | `model_maintenance` | Модель на обслуживании и не принимает запросы; пока идёт обслуживание, другая модель вместо неё не ответит. | Повторите, когда обслуживание закончится; ход работ — на [странице статуса](https://nezhagate.com/ru/status). |

### Загрузка и резерв

| HTTP | code | Причина | Что делать |
| --- | --- | --- | --- |
| **402** | `insufficient_quota` | Баланса не хватает, чтобы зарезервировать стоимость этого запроса. Шлюз сначала резервирует максимально возможную стоимость запроса, поэтому ошибка может возникнуть и при всплеске одновременных вызовов. | Если был всплеск запросов, подождите несколько секунд и повторите; в остальных случаях пополните баланс. |
| **429** | `rate_limit_exceeded` | Все линии этой модели заняты, и запрос не был отправлен. Бывает только на эндпоинтах чата: задачи изображений и видео не отклоняются, а встают в очередь. OpenAI-совместимые эндпоинты добавляют `Retry-After`. | Подождите столько секунд, сколько указано в `Retry-After`, и повторите. |
| **503** | `service_unavailable` | Временный сбой на нашей стороне, например при сохранении референсного файла; `/v1/responses` также отвечает 503 с `Retry-After`, когда свободной линии временно нет. | Повторите чуть позже. |

### Ошибки поставщика (эндпоинты чата)

Если эндпоинт чата (`/v1/chat/completions`, `/v1/responses`, `/anthropic/v1/messages`) получает ошибку, шлюз сначала повторяет запрос на других линиях и возвращает одну из этих ошибок, только когда ошибкой завершились все линии. Ни одна из них не оплачивается.

| HTTP | code | Причина | Что делать |
| --- | --- | --- | --- |
| **502** | `upstream_timeout` | Линия не уложилась в таймаут, в том числе слишком долго не отправляла первый токен. | Повторите; для длинных ответов используйте `stream: true`. |
| **502** | `upstream_unavailable` | Линия дала сбой или временно недоступна. | Повторите чуть позже. |
| **502** | `upstream_busy` | Поставщик модели ограничивает частоту запросов. Его 429 никогда не передаётся вам как 429 — вместо этого вы получаете этот 502. | Повторите чуть позже. |
| **502** | `upstream_connection_error` | Соединение с поставщиком модели оборвалось. | Повторите. |
| **502** | `empty_completion` | Поставщик модели вернул пустой ответ. Это не оценка вашего контента. | Повторите. |
| **502** | `upstream_error` | Вместо ответа линия вернула фразу об ошибке. | Повторите. |
| **400** | `content_filter` | Модель обработала запрос, но ничего не вернула — обычно потому, что контент попал под политику безопасности поставщика. | Измените промпт и повторите; тот же промпт обычно отклоняется снова. |
| **502** | `upstream_prompt_filter` | Промпт остановила предварительная проверка поставщика. Это не оценка контента самой моделью. | Повторите чуть позже или немного измените формулировку. |
| **4xx** | — | Поставщик модели отклонил запрос (например, из-за слишком длинного контекста или неподдерживаемого параметра); статус и `message` передаются в том виде, в каком их прислал поставщик, а в `code` — его значение. | Измените запрос согласно `message`. |

### Эндпоинты Anthropic

- `error.type` принимает стандартные значения Anthropic в зависимости от статуса: 400 `invalid_request_error`, 401 `authentication_error`, 402 `billing_error`, 403 `permission_error`, 404 `not_found_error`, 429 `rate_limit_error` (`overloaded_error`, когда заняты все линии), 502 `api_error`, 503 `overloaded_error` (`api_error`, пока модель на обслуживании).

- `/anthropic` принимает только модели Claude; на любую другую модель вернётся 404 `not_found_error`.

- `max_tokens` обязателен и не может быть равен 0, иначе вернётся 400.

## Неудачные задачи (изображения и видео)

Если задача изображения или видео завершилась ошибкой уже после того, как была принята, эндпоинт задачи всё равно отвечает HTTP 200, а `status` равен `failed`; причина — в `error`, а `error.code` принимает одно из значений ниже. Зарезервированные под задачу кредиты уже вернулись на баланс. С вебхуком вы получите `image.failed` / `video.failed` с тем же содержимым.

| code | Когда возникает | Что делать |
| --- | --- | --- |
| `content_policy` | Видео: промпт, референс или сгенерированный видеоряд либо звук не прошли проверку контента (если отклонён звук, `param` равен `audio`). | Перепишите промпт или замените референс и только потом отправляйте снова: те же входные данные будут отклонены повторно. |
| `moderation_blocked` | Изображение: система безопасности поставщика модели отклонила промпт или референсное изображение (код может быть и `content_policy_violation`). | Перепишите промпт или замените референс; повторная отправка без изменений обычно снова отклоняется. |
| `render_failed` | Видео: на этот раз ролик не получился; обычно это разовый сбой. | Повторная отправка того же запроса обычно проходит успешно. |
| `invalid_material` | Видео: поставщик обнаружил проблему во входных данных. Это общая ошибка, и часто она разовая. | Сначала отправьте задачу ещё раз без изменений; если ошибка повторяется, проверьте референсы и длину промпта. |
| `render_timeout` | Видео: очередь или рендер заняли слишком много времени, и поставщик отказался от задачи. | Отправьте задачу заново. |
| `wait_timeout` | Видео: ролик не пришёл за максимальное время ожидания, которое допускает линия. | Отправьте задачу заново. |
| `upstream_unstable` | Видео: во время рендера оборвалось соединение. | Отправьте задачу заново. |
| `result_fetch_failed` | Видео создано, но на нашей стороне его так и не удалось скачать или сохранить, несмотря на повторные попытки. | Отправьте задачу заново. |
| `invalid_request` | Видео: линия не принимает такое сочетание параметров (например, длительности, пропорции и разрешения). | Измените параметры согласно `message` и отправьте снова. |
| `upstream_error` | Любая другая ошибка: перепробованы все линии, задача ждала 15 минут и так и не запустилась, поставщик отказал без объяснения причины и т. п.; что именно произошло, указано в `message`. | Обычно повторная отправка проходит успешно. |

[Полное руководство по асинхронным задачам →](https://nezhagate.com/ru/docs/guide/async-jobs)

## Ошибки посреди потока

- Когда потоковый запрос уже ответил HTTP 200 и начал передачу, последующая ошибка не может изменить статус: она либо приходит как событие данных с `error`, либо поток просто заканчивается.

- Проверяйте, что поток пришёл целиком: в формате OpenAI должны прийти `finish_reason` и `data: [DONE]`, в формате Anthropic — `message_stop`. Если их нет, считайте поток оборванным.

- Оборвавшийся поток оплачивается по объёму, сгенерированному до обрыва; подробнее — в разделе [Оплата и возвраты](https://nezhagate.com/ru/docs/guide/billing).

## Оплачиваются ли ошибки?

- Запрос, вернувший ошибку, никогда не оплачивается: либо ошибка возникает до списания, либо резерв возвращается полностью.

- За неудачные задачи изображений и видео деньги возвращаются полностью.

- Единственное исключение — поток, который уже начался: если он оборвётся, вы платите за то, что успело сгенерироваться до обрыва.

## Когда повторять запрос

При 4xx сначала исправьте запрос (при 402 пополните баланс, при 429 немного подождите); ошибки 5xx и таймауты можно повторять без изменений, с экспоненциальной задержкой, а если есть `Retry-After` — ждать столько, сколько в нём указано.

[Стратегия повторов и пример кода →](https://nezhagate.com/ru/docs/guide/rate-limits#retry)
