---
title: Ошибки
description: Конверт, в котором приходит отказ, коды ответа шлюза и два поведения, вокруг которых обязан быть написан клиент.
keywords: ошибки, коды ответа, 401, 429, конверт, стриминг, переключение
group: gateway
---

## Конверт отказа {#envelope keywords="ошибка, конверт, type, message, param, json"}

Отклонённый вызов отвечает одним JSON-объектом с единственным членом `error`. Это собственный конверт протокола, а не перевод чужого: одна и та же форма отказывает вызову Chat Completions, вызову Responses и вызову Messages, а поверхность Messages оборачивает её верхнеуровневым `"type": "error"`, которого ждут её клиенты.

Два члена есть всегда — `type` и `message`; ещё два появляются, когда есть что сказать.

| Член | Что несёт |
| --- | --- |
| `type` | Класс отказа в собственном закрытом словаре протокола: invalid_request_error, not_found_error, authentication_error, permission_error, rate_limit_error, api_error, а на поверхности Messages ещё и overloaded_error. |
| `message` | Что пошло не так — фиксированной безопасной фразой. Она никогда не собирается из того, что нёс запрос, поэтому не может процитировать в лог ни промпт, ни заголовок, ни ключ. |
| `code` | Машиночитаемая причина. У одной причины одно написание на всех поверхностях платформы — потому именно на неё и ветвится клиент. |
| `param` | Член запроса, в котором дело, — когда дело в одном члене. |

Ветвитесь на `type` и на `code`, но никогда — на формулировке `message`: она выбрана так, чтобы её было безопасно печатать, а не так, чтобы её разбирали.

```json title=Отказ
{
  "error": {
    "type": "authentication_error",
    "message": "The request is not authenticated."
  }
}
```

## Коды ответа {#error-codes keywords="400, 401, 403, 404, 429, 500, 503, статус"}

| Код | Что означает |
| --- | --- |
| `400` | Запрос невалиден: искажённое тело или член, которого эта поверхность не принимает. |
| `401` | Запрос не аутентифицирован. |
| `403` | Ключу не разрешено вызывать эту модель, либо организация заморожена. |
| `404` | Такой модели нет. |
| `429` | Запрос отклонён лимитом темпа или лимитом трат. |
| `500` | Запрос не удалось выполнить. |
| `503` | Ни один провайдер сейчас не может обслужить этот запрос. |

Два из них стоит различать до того, как написан повтор. `429` — это потолок, выше которого вы оказались, и лечит его время; `503` — это то, что сейчас вызов не может обслужить никто наверху. Ни один из них не лечится немедленным повтором, а клиент, считающий любой отказ поводом «повторить сейчас же», тратит на отказы всю свою квоту.

## Один 401 на любую беду с ключом {#key-refusals keywords="401, отказ, отозван, истёк, неизвестен"}

На отсутствующий, искажённый, неизвестный, отозванный и истёкший ключ ответ одинаковый — тот же `401` и та же фраза, — и это решение, а не недоделка. Различать их значило бы превратить шлюз в оракул по ключевому материалу: тот, кто видит разницу между «такого ключа нет» и «этот ключ отозван», читает таблицу ключей платформы по одной догадке за раз.

Поэтому `401` говорит ровно одно: вызов не допущен. Проверьте, что заголовок на месте и записан как bearer-токен, что ключ — это целиком тот секрет, который вы скопировали при выпуске, и что ключ ещё жив. Проверка ключа отвечает на все три вопроса сразу, из браузера и без единой строки кода.

> [Проверить ключ →](page:key-check) · [Как пишется заголовок →](page:authentication)

## Когда поток обрывается раньше срока {#stream-failure keywords="стриминг, sse, done, обрыв, неполный ответ"}

Отказ, решённый до первого события, приходит обычной JSON-ошибкой со статусом — ровно так же, как ответили бы на неразбитый на события вызов: тот самый конверт, и ничего в потоке. Сбой после начала потока таким быть уже не может: строка статуса ушла раньше. Такой поток просто заканчивается — **без** завершающего кадра `[DONE]`.

Этим отсутствием всё и сказано, поэтому читать нужно именно его. Клиент, который считает, что «соединение закрылось» значит «ответ дописан», отдаст дальше усечённый ответ, и в полученных им байтах ничто не скажет обратного. Считайте поток, кончившийся до `[DONE]`, неудавшимся вызовом, а не коротким.

Две другие поверхности говорят то же своими событиями: на поверхности Messages сбой приходит событием ошибки этого протокола, и дальше поток кончается без `message_stop`, а на поверхности Responses завершающее событие — `response.failed`, несущее этот конверт вместо готового тела.

## Переключение {#failover keywords="переключение, канал, провайдер, повтор"}

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

Три вида отказа вызов не переносят, а завершают. Отказ после того, как до вас дошли первые байты, — нельзя выдать второй ответ посреди того, который вы уже читаете. Отменённый вами вызов — вы его больше не ждёте. И вызов, исход которого наверху неизвестен: повтор мог бы выставить счёт дважды за работу, которая на самом деле удалась.

Поэтому `503` не обещает, что перепробованы все маршруты. Он приходит и тогда, когда ни один канал не подходит под то, о чём просил вызов, — ещё до обращения наверх, — а число каналов, которое переберёт один вызов, ограничено, а не исчерпывающе.

> [Чем ограничена пропускная способность →](page:limits)
