Ошибки
Формат тела
Ошибочные ответы не используют один общий конверт. Есть три формы:
1. Доменные ошибки (бросаются через onError) используют стандартный конверт:
{ "error": { "code": "invalid_credentials", "message": "Invalid credentials" } }code — стабильная машиночитаемая строка; message — человекочитаемая и может меняться.
2. Ошибки валидации 400 (Zod-валидация Hono) используют собственный формат валидатора, без code:
{ "success": false, "error": { "issues": [ … ], "name": "ZodError" } }3. Некоторые ответы 401/403 (подпись вебхука, владение api-key) возвращают плоскую строку, а не объект:
{ "error": "Missing signature" }{ "error": "Forbidden" }Рекомендация: матчите в первую очередь по HTTP-статусу; code считайте вторичным — он отсутствует у ошибок валидации и у «плоских» ответов, а message может меняться.
Таблица кодов статусов
| Статус | code | Возникает, когда | Как обработать |
|---|---|---|---|
400 | — (формат Zod) | Не прошла валидация (тело/схема) | Исправьте payload; проверьте обязательные поля |
401 | invalid_credentials | Вход с неверным email/паролем | Запросите учётные данные заново |
401 | unauthorized | Отсутствует/невалидна сессия, сессия отозвана, клиент приостановлен, невалидный токен | Аутентифицируйтесь заново (войдите ещё раз) |
401 | error | Отсутствует/невалиден/отозван API-ключ | Проверьте заголовок ключа |
401 | — (плоская строка) | Отсутствует/невалидна подпись вебхука ({"error":"Missing signature"} / {"error":"Invalid signature"}) | Проверьте заголовок X-YooKassa-Signature |
402 | insufficient_balance | Резервирование/списание/корректировка ушли бы в минус | Пополните баланс и повторите |
403 | forbidden (reserved) | ForbiddenError определён в error-map, но в beta не бросается | — |
403 | error | Несовпадение владельца/роли на admin-маршрутах, CSRF (Invalid origin / Missing origin), недостаточный скоуп, воркспейс/клиент приостановлены | Убедитесь, что ресурс ваш; передайте валидный Origin; выдайте нужный скоуп |
403 | — (плоская строка) | Несовпадение владельца API-ключа ({"error":"Forbidden"}) | Убедитесь, что ключ принадлежит воркспейсу |
404 | not_found | Неизвестная модель, неизвестный воркспейс, неизвестный API-ключ, нет прайса для модели | Проверьте идентификатор |
409 | email_already_registered | Регистрация с уже существующим email | Войдите вместо регистрации |
429 | quota_exceeded (reserved) | Достигнут лимит квоты — reserved: в beta не возвращается (квота enforced атомарным пропуском инкремента, а не отклонением запроса) | Снизьте потребление или поднимите квоту |
429 | error | Превышен rate limit (по ключу или на auth) | Отступите и повторите после X-RateLimit-Reset |
500 | internal_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).
Подробнее — в разделе Лимиты и квоты.