Skip to content

Ошибки

Формат тела

Ошибочные ответы не используют один общий конверт. Есть три формы:

1. Доменные ошибки (бросаются через onError) используют стандартный конверт:

json
{ "error": { "code": "invalid_credentials", "message": "Invalid credentials" } }

code — стабильная машиночитаемая строка; message — человекочитаемая и может меняться.

2. Ошибки валидации 400 (Zod-валидация Hono) используют собственный формат валидатора, без code:

json
{ "success": false, "error": { "issues": [  ], "name": "ZodError" } }

3. Некоторые ответы 401/403 (подпись вебхука, владение api-key) возвращают плоскую строку, а не объект:

json
{ "error": "Missing signature" }
json
{ "error": "Forbidden" }

Рекомендация: матчите в первую очередь по HTTP-статусу; code считайте вторичным — он отсутствует у ошибок валидации и у «плоских» ответов, а message может меняться.

Таблица кодов статусов

СтатусcodeВозникает, когдаКак обработать
400— (формат Zod)Не прошла валидация (тело/схема)Исправьте payload; проверьте обязательные поля
401invalid_credentialsВход с неверным email/паролемЗапросите учётные данные заново
401unauthorizedОтсутствует/невалидна сессия, сессия отозвана, клиент приостановлен, невалидный токенАутентифицируйтесь заново (войдите ещё раз)
401errorОтсутствует/невалиден/отозван API-ключПроверьте заголовок ключа
401— (плоская строка)Отсутствует/невалидна подпись вебхука ({"error":"Missing signature"} / {"error":"Invalid signature"})Проверьте заголовок X-YooKassa-Signature
402insufficient_balanceРезервирование/списание/корректировка ушли бы в минусПополните баланс и повторите
403forbidden (reserved)ForbiddenError определён в error-map, но в beta не бросается
403errorНесовпадение владельца/роли на admin-маршрутах, CSRF (Invalid origin / Missing origin), недостаточный скоуп, воркспейс/клиент приостановленыУбедитесь, что ресурс ваш; передайте валидный Origin; выдайте нужный скоуп
403— (плоская строка)Несовпадение владельца API-ключа ({"error":"Forbidden"})Убедитесь, что ключ принадлежит воркспейсу
404not_foundНеизвестная модель, неизвестный воркспейс, неизвестный API-ключ, нет прайса для моделиПроверьте идентификатор
409email_already_registeredРегистрация с уже существующим emailВойдите вместо регистрации
429quota_exceeded (reserved)Достигнут лимит квоты — reserved: в beta не возвращается (квота enforced атомарным пропуском инкремента, а не отклонением запроса)Снизьте потребление или поднимите квоту
429errorПревышен rate limit (по ключу или на auth)Отступите и повторите после X-RateLimit-Reset
500internal_errorНеобработанная ошибка сервераПовторите с backoff; сообщите

Reserved-коды. quota_exceeded и forbidden есть в error-map, но в beta не возвращаются. Квоты enforced атомарно (инкремент потребления пропускается при превышении, поэтому запрос не падает с 429). На практике 403 приходит как конверт с кодом error (владение/CSRF/скоуп) либо как плоская строка {"error":"Forbidden"} (владение api-key).

Рекомендации по обработке

  • Повторяйте только идемпотентные запросы. Вебхуки идемпотентны по замыслу; chat completions небезопасно «вслепую» повторять (каждый повтор биллится).
  • 401 на сессии означает, что cookie утеряна, отозвана или истекла — войдите заново, не зацикливайтесь.
  • 402 — это проблема баланса, а не баг: резервирование или дефицит не удалось покрыть.
  • 403 insufficient scope возвращается как обычный error-код с сообщением вида Insufficient scope: chat:write required — проверьте скоупы ключа.
  • 429 на пути chat несёт заголовки rate limit (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) — читайте их перед повтором.

Особенности auth и rate limit

  • Auth rate limiting применяется к POST /v1/auth/login (10/мин/IP) и POST /v1/auth/register (5/мин/IP), возвращая 429 с кодом error (Too many attempts).
  • Rate limit по ключу применяется к POST /v1/chat/completions, возвращая 429 с кодом error (Rate limit exceeded).

Подробнее — в разделе Лимиты и квоты.