Все статьи

Коды ошибок LLM API у разных провайдеров: справочник по 4xx/5xx, стратегии повторов и граничные случаи

Практический справочник по HTTP-ошибкам API OpenAI, Anthropic, DeepSeek и DashScope. Мы сравнили ошибки аутентификации, варианты rate-limit, отказы фильтров контента, ответы при отсутствии модели и ошибки внутри SSE-потоков — а затем построили дерево решений: когда повторять запрос, когда переключаться на другого провайдера и когда сразу возвращать ошибку.

· TheRouter

Каждый LLM API возвращает ошибки по-разному. OpenAI использует четыре варианта 429. Anthropic ввёл 529. DeepSeek выделил отдельный 402. DashScope оборачивает ошибки в конверт code/message, который иногда противоречит HTTP-статусу.

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

OpenAI-совместимость означает, что провайдер предоставляет endpoint chat-completions, чей контракт запроса и ответа достаточно близок к API OpenAI, чтобы немодифицированный вызов OpenAI SDK работал после замены трёх значений: API key, base URL, название модели. Минимальная поверхность на практике —POST /v1/chat/completions с messages, model и потоковым ответом в форме OpenAI.

TL;DR — сводная таблица кодов ошибок

HTTP-статусТип ошибкиOpenAIAnthropicDeepSeekDashScopeПовтор?Рекомендуемое действие
400Некорректный запросinvalid_request_errorinvalid_request_errorInvalid Format / Invalid Parameters (422)InvalidParameterНетИсправить тело запроса
401Аутентификацияinvalid_authenticationauthentication_errorAuthentication FailsInvalidApiKey (HTTP 400)НетПроверить API key
402БиллингInsufficient BalanceНетПополнить баланс
403Доступcountry_not_supportedpermission_errorНетПроверить доступ/регион
404Не найденоnot_found_errorModelNotFoundНетИсправить model ID
413Слишком большойrequest_too_largeНетУменьшить входные данные
429Rate limitrate_limit_error + 3 billing-вариантаrate_limit_errorRate Limit ReachedThrottling / FlowControlДа (rate); Нет (billing)Backoff; проверить Retry-After
500Ошибка сервераserver_errorapi_errorServer ErrorInternalErrorДаПовтор с backoff
503Перегрузкаoverloaded / slow_downServer OverloadedServiceUnavailableДаПовтор с backoff
529Перегрузкаoverloaded_errorДаПовтор с backoff

Данные получены 31 июля 2026. OpenAI — developers.openai.com/api/docs/guides/error-codes. Anthropic — platform.claude.com/docs/en/api/errors и github.com/anthropics/skills. DeepSeek — api-docs.deepseek.com/quick_start/error_codes. DashScope — alibabacloud.com/help/en/model-studio/error-code.

Ошибки аутентификации: 401 vs 403

Ошибки аутентификации никогда не подлежат повтору, но провайдеры сигнализируют о них по-разному.

OpenAI возвращает 401 для четырёх причин: невалидный key, неправильный формат key, отсутствие членства в организации и несовпадение IP-whitelist. Также используется 403 для неподдерживаемых стран/регионов — это географическое ограничение, а не проблема учётных данных.

Anthropic чётко разделяет 401 (аутентификация — неправильный или отсутствующий key) и 403 (разрешения — key не имеет доступа к конкретной модели или beta-функции). Важная деталь: если вы передадите OAuth bearer token через x-api-key вместо Authorization: Bearer, вы получите 401, а не 403.

DeepSeek возвращает 401 для всех сбоев аутентификации. 403 в документированной поверхности ошибок не используется.

DashScope возвращает 400 с кодом InvalidApiKey для сбоев аутентификации — не 401. Это особенность их конверта ошибок: HTTP-статус 400, но семантический код ошибки внутри тела ответа указывает на проблему аутентификации. Если вы парсите только HTTP-статусы, вы ошибочно классифицируете это как «некорректный запрос».

Практический вывод

Не полагайтесь на HTTP 401 для обнаружения сбоев аутентификации у разных провайдеров. Парсите тело ошибки. InvalidApiKey от DashScope приходит как 400.

Ошибки rate-limit: разновидности 429

Rate-limit — самая сложная категория, потому что провайдеры перегружают 429 для принципиально разных проблем.

OpenAI: четыре типа 429

OpenAI возвращает 429 для четырёх причин, каждая с отдельным error.code:

  1. rate_limit_reached — превышен RPM или TPM. Можно повторить после интервала из заголовка Retry-After.
  2. credit_balance_exhausted — предоплаченные кредиты исчерпаны. Повтор бесполезен; нужно пополнить.
  3. organization_spend_limit_exceeded — лимит расходов организации. Повтор бесполезен; нужно поднять лимит.
  4. project_spend_limit_exceeded — лимит расходов проекта. Повтор бесполезен; нужно поднять лимит.

Ключевое отличие: только первый тип подлежит повтору. Остальные три требуют действий на уровне аккаунта. Повторные запросы для billing-вариантов 429 с exponential backoff — пустая трата ресурсов.

Anthropic: чистый 429 + уникальный 529

Anthropic использует 429 только для rate limit (RPM, ITPM, OTPM). Они предоставляют заголовки retry-after, x-ratelimit-limit-* и x-ratelimit-remaining-*. SDK автоматически повторяет 429 и 5xx с exponential backoff (по умолчанию 2 повтора).

Уникальное решение Anthropic: 529 overloaded_error для исчерпания ёмкости. Это отличается от 500 api_error (баг сервера). Оба подлежат повтору, но 529 конкретно означает «мы заняты, попробуйте позже» — а не «что-то сломалось».

DeepSeek: 429 для rate-limit, 402 для биллинга

DeepSeek сохраняет простоту: 429 — rate limit, 402 — недостаточный баланс. Никаких billing-вариантов 429. 402 — ясный сигнал: прекратить повторы и пополнить счёт.

DashScope: Throttling vs FlowControl

DashScope возвращает 429 с двумя внутренними кодами: Throttling (превышен QPM/TPM для конкретной модели) и FlowControl (системный flow-контроль при высокой нагрузке). Оба подлежат повтору, но FlowControl может означать более долгое ожидание. DashScope также поддерживает временное повышение лимитов через консоль.

Ошибки фильтрации контента

Отказы фильтра контента приходят как 400 у всех провайдеров, но с разными внутренними кодами:

  • OpenAI: 400 с упоминанием content_filter в сообщении. В streaming — finish reason content_filter в chunk.
  • Anthropic: 400 invalid_request_error при нарушении политики использования. Отдельного типа ошибки нет.
  • DeepSeek: 400 Invalid Format с сообщением о нарушении политики контента.
  • DashScope: 400 с кодом DataInspectionFailed — самый описательный код из четырёх.

Ошибки фильтрации контента никогда не подлежат повтору с тем же входом. Необходимо изменить содержимое запроса.

Ошибки «модель не найдена» и устаревшие модели

Когда вы запрашиваете несуществующую или устаревшую модель:

  • OpenAI: 404 с сообщением, перечисляющим model ID и предлагающим альтернативы.
  • Anthropic: 404 not_found_error. Частая причина: опечатка в model ID (например, claude-sonnet-4.6 вместо claude-sonnet-4-6). Алиасы вроде claude-opus-5 работают.
  • DeepSeek: документированного 404 нет — пространство моделей DeepSeek невелико и стабильно.
  • DashScope: 400 с кодом ModelNotFound или InvalidModel. После даты вывода модели запросы возвращают эту ошибку.

Плавная деградация для устаревших моделей

Если вы маршрутизируете через несколько провайдеров, ошибка «модель не найдена» должна запускать fallback на эквивалентную модель — а не повтор. См. руководство по fallback-маршрутизации.

Ошибки внутри SSE-потоков

Streaming (SSE) создаёт тонкую проблему: HTTP-соединение возвращает 200 при начальном handshake, но ошибки могут возникнуть в середине потока, когда вы уже обрабатываете chunk-и.

  • OpenAI: может отправить событие ошибки внутри SSE-потока. Начальный HTTP-статус — 200, поэтому нужно проверять каждый chunk. Поток может просто оборваться без маркера [DONE] при серверных ошибках.
  • Anthropic: отправляет content_block_stop или message_stop при успехе и отдельный тип события error при неудаче. Типизированный протокол делает обнаружение ошибок чётче.
  • DeepSeek: следует OpenAI-совместимому SSE-формату. Ошибки в середине потока приходят как error-chunk-и.
  • DashScope: при использовании OpenAI-совместимого endpoint следует тому же шаблону SSE-ошибок, что и OpenAI.

Подробнее — в руководстве по cross-provider streaming.

Практический вывод

Никогда не считайте HTTP 200 гарантией успеха всего ответа. Всегда реализуйте обработку ошибок на уровне потока.

Нормализация ошибок в gateway

При маршрутизации запросов между провайдерами разнородные форматы ошибок — реальная проблема: клиентскому коду нужно N обработчиков для N провайдеров. Routing gateway должен нормализовать upstream-ошибки в единый downstream-контракт.

Рекомендуемое сопоставление:

Downstream-классИсточникПовторДействие
auth_error401, 403, DashScope InvalidApiKeyНетИсправить учётные данные
invalid_request400 (кроме фильтра контента), 413, 422НетИсправить запрос
content_filtered400 + флаг политики контентаНетИзменить контент
rate_limited429 (только rate-варианты)ДаBackoff + повтор
billing_error402, 429 (billing-варианты)НетПополнить / поднять лимит
model_unavailable404, ModelNotFoundНетFallback на другую модель
provider_error500, 503, 529ДаПовтор → fallback

Сохраняйте оригинальный код ошибки и сообщение провайдера в поле метаданных. Разработчикам, отлаживающим инцидент в production, нужно видеть исходный credit_balance_exhausted, а не просто «billing_error».

TheRouter маршрутизирует OpenAI-совместимые запросы через настроенных провайдеров и поддерживает fallback моделей при наличии рабочих путей. Нормализация ошибок — часть routing-контракта: upstream 429 и 5xx запускают fallback-цепочки при настройке.

Дерево решений: повтор vs fallback vs fail

Получена ошибка
├── HTTP-статус 429?
│   ├── error.code — billing/spend/credit?
│   │   └── FAIL — повтор бесполезен; нужно действие на уровне аккаунта
│   └── error.code — rate-limit?
│       ├── Есть заголовок Retry-After?
│       │   └── ЖДАТЬ указанное время, затем ПОВТОРИТЬ у того же провайдера
│       └── Нет Retry-After
│           └── ПОВТОРИТЬ с exponential backoff (макс. 3 попытки)
│               └── Всё ещё ошибка? → FALLBACK на следующего провайдера
├── HTTP-статус 500, 503 или 529?
│   └── ПОВТОРИТЬ с exponential backoff (макс. 3 попытки)
│       └── Всё ещё ошибка? → FALLBACK на следующего провайдера
├── HTTP-статус 400 (фильтр контента)?
│   └── FAIL — контент нужно изменить; fallback не поможет
├── HTTP-статус 400, 401, 403, 404, 413 или 422?
│   └── FAIL — проблема клиента; исправить запрос
└── HTTP-статус 402?
    └── FAIL — проблема биллинга; пополнить баланс

Часто задаваемые вопросы

Какие ошибки LLM API безопасно повторять?

HTTP 429 (только rate-limit, не billing-варианты), 500 (ошибка сервера), 503 (перегрузка) и 529 (перегрузка Anthropic) обычно безопасны для повтора с exponential backoff. Все ошибки 400-серии, кроме rate-limit 429, требуют клиентских изменений. См. сравнение rate-limit.

Почему OpenAI возвращает разные типы ошибок 429?

OpenAI использует 429 минимум для четырёх разных причин: RPM/TPM rate limit, исчерпание кредитов, лимит расходов организации и лимит расходов проекта. Проверяйте поле error.code: rate_limit_reached, credit_balance_exhausted, organization_spend_limit_exceeded и project_spend_limit_exceeded. Только rate_limit_reached подлежит повтору.

Что такое код 529 у Anthropic?

Anthropic возвращает HTTP 529 (overloaded_error), когда API временно достиг предела нагрузки. Это отличается от 500 (api_error, означает баг сервера). Оба подлежат повтору с exponential backoff. При постоянных 529 рассмотрите маршрутизацию к менее нагруженной модели — модели класса Haiku обычно имеют больше доступной ёмкости.

Чем подход DeepSeek к недостаточному балансу отличается от OpenAI?

DeepSeek возвращает выделенный HTTP 402 (Insufficient Balance), тогда как OpenAI объединяет это в 429 с кодом credit_balance_exhausted. Подход DeepSeek яснее — 402 никогда не подлежит повтору и всегда означает необходимость пополнения.

Различается ли сигнализация ошибок внутри SSE-потоков?

Да. Все провайдеры могут вернуть HTTP 200 для начального SSE-соединения, но затем отправить ошибку внутри потока. Всегда реализуйте обработку ошибок на уровне потока — не полагайтесь на 200 как на гарантию. См. руководство по streaming.

Как routing gateway нормализовать ошибки?

Сопоставьте upstream-ошибки с единым downstream-контрактом: auth_error, invalid_request, rate_limited, content_filtered, model_unavailable или provider_error. Сохраняйте оригинальный код и сообщение в метаданных. Так клиент пишет один retry/fallback-обработчик. См. сравнение gateway.

Где проверить статус провайдеров при сбоях?

Поддержка