Справочник
Ошибки
Все ответы не из 2xx используют один конверт. HTTP-статус и поле error.type вместе говорят, что делать — повторить, отложить, починить вход или остановиться.
Конверт ошибки
Любой ответ с ошибкой — это JSON одной и той же формы. Верхний type всегда литеральная строка "error"; смысл — в error.type.
{
"type": "error",
"error": {
"type": "invalid_request_error",
"message": "max_tokens must be a positive integer."
}
}Коды статуса
| HTTP | type | Когда возникает |
|---|---|---|
| 400 | invalid_request_error | Тело запроса невалидно или нарушает ограничение (неизвестная модель, слишком большой max_tokens, кривой массив messages). Не повторяй — чини вход. |
| 401 | authentication_error | API-ключ отсутствует, искажён или невалиден. Не повторяй как есть — переаутентифицируйся. |
| 402 | insufficient_quota | Баланс apiCredits ниже, чем нужно для этого поворота. Жёсткий стоп. Пополни на /developers/billing. |
| 403 | permission_error | Ключ аутентифицирован, но не допущен на эту поверхность (CLI-ключ на /v1/*, аккаунт приостановлен, не совпадают скоупы). |
| 404 | not_found_error | Путь или ресурс не существует. Проверь URL и id модели. |
| 413 | request_too_large | Тело превысило лимит запроса в 16 МБ. Раздроби payload или уменьши изображения. |
| 429 | rate_limit_error | Поймал лимит per-key. Уважай Retry-After. Кредиты не списываются. |
| 500 | api_error | Внутренний сбой у нас. Повтори с backoff. Идемпотентно. |
| 502 | api_error | Вышестоящий провайдер вернул ошибку. Повтори с backoff. |
| 503 | api_error | Сервис временно недоступен (деплой, обслуживание). Повтори с backoff. |
| 504 | api_error | Провайдер вышел по таймауту. Повтори с backoff. Можно понизить max_tokens. |
| 529 | overloaded_error | Перегрузка по мощности на вышестоящей модели. Повтори с backoff. Часто проходит за несколько секунд. |
Как работать с каждым классом
- Можно повторять: 429, 500, 502, 503, 504, 529. Экспоненциальный backoff с джиттером. Если есть
Retry-After— уважай. Не больше 4–6 попыток. - Жёсткий стоп: 402 (
insufficient_quota) и 401/403 (authentication_error,permission_error). Никакие ретраи не помогут. Эскалируй человеку или в алертинг. - Чинить вход: 400 (
invalid_request_error) и 413. В следующий раз валидируй до отправки; правь вызывающую сторону.
Идентификаторы сообщений
Каждый успешный ответ несёт поле id (например, msg_01H8fkx2N3p4q5r6s7t8u9v0wx на /v1/messages, chatcmpl_... на /v1/chat/completions). Сохраняй id на каждом вызове. При обращении в поддержку id — самый быстрый способ для нас отследить весь жизненный цикл запроса: какой провайдер выбран, что было зарезервировано и что в итоге списано.
Маленький переиспользуемый обработчик
Заверни каждое место вызова в функцию, которая раскладывает ответ по трём ведёркам выше. Пример ниже отличает insufficient_quota (не повторяй) от rate_limit_error (повтори) и от транзиентных ошибок провайдера (повтори). Стратегию ретраев выбирает вызывающий.
# Inspect the type field to decide what to do.
status=$(curl -s -o /tmp/body -w "%{http_code}" \
-X POST https://caicaini.com/v1/messages \
-H "Authorization: Bearer cai_api_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"caicaini/auto","max_tokens":50,"messages":[{"role":"user","content":"Hi"}]}')
errtype=$(jq -r '.error.type // empty' /tmp/body 2>/dev/null)
echo "status=$status type=$errtype"
case "$status$errtype" in
200*) echo "ok" ;;
402*|*insufficient_quota) echo "top up at /developers/billing"; exit 2 ;;
429*|*rate_limit_error) echo "throttled — sleep, then retry" ;;
500*|502*|503*|504*|529*) echo "transient — retry with backoff" ;;
*) echo "fatal — fix the request"; exit 1 ;;
esacСвязанное
- Лимиты запросов — полная стратегия backoff и таблица тарифов.
- Аутентификация — что на самом деле значит 401.
- Цены и кредиты — как 402 выглядит на практике.