Ошибки API
Формат ошибки определяется адресом, на который ушёл запрос. ID запроса есть в каждой ошибке.
Формат ошибок
Для /v1/chat/completions, /v1/responses и остальных адресов ошибка приходит в формате OpenAI:
{
"error": {
"message": "Invalid or missing API key. Request ID: req_0be8…",
"type": "authentication_error",
"code": "authentication_error",
"request_id": "req_0be8…"
}
}Для /v1/messages ошибка приходит в формате Anthropic; его разбирают SDK Anthropic и Claude Code:
{
"type": "error",
"error": {
"type": "authentication_error",
"message": "Invalid or missing API key. Request ID: req_0be8…"
},
"request_id": "req_0be8…"
}ID запроса лежит в поле request_id, в конце текста сообщения и в заголовке X-Request-Id. Приложите его к обращению в поддержку, по нему мы найдём запрос.
Коды ошибок
Значения в колонке code относятся к формату OpenAI. В формате Anthropic ту же причину выдают HTTP-статус и тип ошибки.
| HTTP | code | Что сделать |
|---|---|---|
400 | model_required bad_request invalid_request | Проверьте JSON и обязательные поля тела запроса. |
400 | model_not_found | Проверьте имя модели в GET /v1/models. |
400 | context_length_exceeded | Уменьшите запрос или выберите модель с более широким контекстом. |
400 | image_input_not_supported | Модель не принимает картинки: нужна модель со зрением. |
400 | content_policy_violation | Запрос нарушает правила использования. |
401 | authentication_error | Ключ неверный, отозван или не передан. На адресах картинок и видео в поле code может прийти unauthorized, а тип остаётся authentication_error. |
402 | insufficient_quota | Пополните баланс. |
402 | account_frozen | Аккаунт приостановлен, напишите в поддержку. |
403 | model_not_in_channel | В канале этого ключа такой модели нет: смените канал ключа или модель. |
404 | not_found | Неизвестный адрес API. |
413 | request_too_large | Тело запроса больше 32 МБ. |
429 | rate_limited family_rate_limited | Запросы идут слишком часто, повторите через несколько секунд. |
429 | org_queue_full | По ключу идёт слишком много запросов одновременно: дождитесь, пока завершатся текущие. |
429 | queue_full queue_timeout | Сервис занят, повторите через несколько секунд. |
429 | low_balance | Баланс почти исчерпан, поэтому запросы идут по одному. Пополните баланс. |
500, 502 | server_error empty_response | Сбой при обработке, повторите запрос. |
503 | model_overloaded | Модель перегружена, повторите позже. |
503 | maintenance auth_unavailable service_unavailable | Сервис временно недоступен, повторите через несколько секунд. |
Ошибки выбора канала (channel_not_allowed, fallback_not_allowed, channel_unavailable, invalid_state) описаны на странице Каналы Premium и Cheap.
Retry-After
В ответах 429 и 503 приходит заголовок Retry-After со временем ожидания в секундах.
Ошибки в стриме
Если сбой произошёл уже после начала стрима, код ответа остался 200, и ошибка приходит отдельным событием:
- в формате OpenAI:
data: {"error": {…}}, затемdata: [DONE]; - в формате Anthropic:
event: errorс телом ошибки; - Responses API: событие
response.failed.
Если ответ модели оборвался на середине, придёт ошибка с кодом upstream_stream_interrupted или stream_incomplete. Ответ неполный, запрос нужно повторить.
Оплата при ошибках
Когда ошибка возникла до начала ответа, деньги не списываются. Когда ответ оборвался на середине, оплачиваются только токены, которые модель успела выдать.
Стратегия повторов
Рекомендуем такой порядок:
- 429 и 503: повторяйте с паузой от 1 секунды и удваивайте её (1, 2, 4, 8 секунд, но не больше 60). Если пришёл Retry-After, ждите ровно столько, сколько он указывает.
- 500 и 502: повторите до 3 раз с паузой в секунду. Если ошибка не уходит, напишите в поддержку и приложите ID запроса.
- 400, 401, 402, 403, 404, 413: повтор не поможет. Исправьте запрос, ключ, баланс или канал.
import time
import requests
def call_api(payload, max_retries=3):
for attempt in range(max_retries):
response = requests.post(
"https://api.codexkey.ru/v1/messages",
headers={
"x-api-key": "sk_cdx_YOUR_KEY",
"anthropic-version": "2023-06-01",
"Content-Type": "application/json",
},
json=payload,
)
if response.status_code == 200:
return response.json()
if response.status_code in (429, 503):
wait = int(response.headers.get("Retry-After", 2 ** attempt))
time.sleep(wait)
continue
if response.status_code in (500, 502):
time.sleep(1)
continue
response.raise_for_status()
raise Exception("Max retries exceeded")