Перейти к содержимому
Обработка ошибок

Обработка ошибок

Запрос, завершившийся сбоем, возвращает HTTP-код статуса и JSON-тело с типом ошибки и сообщением. На этой странице перечислены все статусы, показано тело ошибки в каждом формате API и указано, какие ошибки стоит повторять.

SDK выбрасывают объект ошибки, который несет код статуса и поля тела. Этот запрос указывает несуществующую модель:

import openai
from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://api.shannon-ai.com/v1",
)

try:
    client.chat.completions.create(
        model="no-such-model",
        messages=[{"role": "user", "content": "Hello"}],
    )
except openai.APIStatusError as error:
    print(error.status_code)                           # 400
    print(error.type)                                  # invalid_request_error
    print(error.body["message"])                       # unknown model: no-such-model
    print(error.response.headers.get("x-request-id"))  # the id of this request

Он возвращает статус 400 и такое тело:

400 JSON
{
  "error": {
    "type": "invalid_request_error",
    "message": "unknown model: no-such-model"
  }
}

Тело ошибки

Есть два вида тела. /v1/messages отвечает в формате Anthropic; все остальные эндпоинты отвечают в формате OpenAI. В обоих подробности находятся в error.type и error.message, поэтому один обработчик подходит для всех эндпоинтов.

401 Формат OpenAI
{
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key",
    "code": "invalid_api_key",
    "param": null
  }
}
401 Формат Anthropic
{
  "type": "error",
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key"
  }
}
Поле Тип Описание
error.type string Вид ошибки. См. ниже «Типы ошибок».
error.message string Предложение для человека. Тексты в таблицах ниже стабильны с точностью до переменных частей, обозначенных как <id>, <n> или ….
error.code string | null Присутствует в некоторых ошибках формата OpenAI: invalid_api_key при 401, request_too_large при 413, context_length_exceeded при слишком длинном разговоре, иначе null или отсутствует. Сначала ориентируйтесь на статус и error.type, а code считайте дополнением.
error.param null Присутствует в тех же ошибках, что и code. Всегда null.
type string Только формат Anthropic. Всегда error.

Типы ошибок

Тип Статусы Описание
invalid_request_error 400, 413, 415, 422 Сам запрос неверен: поле, тело, id модели или ввод, который модель не принимает. Измените запрос, прежде чем отправлять его снова.
authentication_error 401 API-ключ отсутствует, неизвестен или отозван.
not_found_error 404 Такого пути не существует.
rate_limit_error 429 Баланса не хватает на запрос, защита от флуда остановила его либо модель занята. Сообщение указывает, что именно.
api_error 500, 502, 503, 504 Запрос был корректным, а сбой произошел на нашей стороне. Отправьте его снова.
server_error 500 Запрос был корректным, а сбой произошел на нашей стороне. Отправьте его снова.

Коды статуса

Статус Тип Сообщение Когда
400 invalid_request_error Failed to parse the request body as JSON: … Тело не является корректным JSON.
400 invalid_request_error unknown model: <id> model не является опубликованным id. На /v1/responses также если model отсутствует.
400 invalid_request_error No user message provided Уровни Shannon: в запросе нет пользовательского текста.
400 invalid_request_error <id> does not accept image input Изображение отправлено размещенной модели с открытыми весами, не поддерживающей ввод изображений.
400 invalid_request_error audio and video input are not supported by any hosted model Аудио- или видеочасть отправлена размещенной модели с открытыми весами.
400 invalid_request_error <id> does not accept response_format Структурированный вывод запрошен у размещенной модели с открытыми весами, которая его не поддерживает.
400 invalid_request_error <id> does not accept response_format json_schema; use json_object JSON-схема отправлена размещенной модели с открытыми весами, которая принимает только json_object.
400 invalid_request_error unknown reasoning effort '<value>'; expected off, low, medium or high Усилие рассуждения не входит в список допустимых значений. Размещенные модели с открытыми весами.
400 invalid_request_error count_tokens is available for the hosted open models; unknown model: <id> Подсчет токенов запрошен для модели, не входящей в размещенные модели с открытыми весами.
401 authentication_error Missing authentication API-ключ не был отправлен.
401 authentication_error Invalid API key Ключ неизвестен, заменен более новым или отозван.
404 not_found_error Not Found Такого пути не существует, например /v1/embeddings.
405 api_error Method Not Allowed Путь существует, но не с этим HTTP-методом.
413 invalid_request_error Failed to buffer the request body: … Тело запроса больше 32 MiB.
415 invalid_request_error Expected request with `Content-Type: application/json` Заголовок Content-Type отсутствует или не равен application/json.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … Отсутствует обязательное поле, например messages, или у поля неверный тип JSON.
429 rate_limit_error Quota exceeded. Upgrade your plan at shannon-ai.com/plan Лимит вывода запроса больше, чем остаток вашего баланса.
429 rate_limit_error Too many requests. Retry in <n>s. Защита от флуда: более 120 запросов в минуту с вашего аккаунта. <n> — число секунд до конца минуты.
429 rate_limit_error Shannon Coder call quota reached. Upgrade your plan at shannon-ai.com/plan shannon-coder-1 на /v1/chat/completions и /v1/messages: вызовы Shannon Coder по вашему плану в текущем 4-часовом окне исчерпаны.
429 rate_limit_error Shannon routes are temporarily busy. Please retry. Модель в данный момент занята.
500 server_error The model backend failed to answer. Please retry. Модель не сформировала ответ.
500 server_error An internal error occurred. Please retry. Внутренний сбой при подготовке запроса.
502 api_error The model backend failed to answer. Please retry. Модель не сформировала ответ. Семейство Shannon 3 и размещенные модели с открытыми весами.
503 api_error Could not verify your quota right now. Please retry. Ваш баланс в данный момент не удалось прочитать.
503 api_error token counting is temporarily unavailable for this model Подсчет токенов для этой модели в данный момент недоступен.
504 api_error upstream timed out Размещенная модель с открытыми весами превысила ограничение по времени для запроса без стриминга.

Проверки выполняются в таком порядке: API-ключ, тело запроса, id модели, защита от флуда, баланс. Поэтому запрос с неверным ключом и неверным телом возвращает 401. Запрос, отклоненный со статусом 4xx, не тарифицируется.

Баланс и защита от флуда

Все запросы обслуживаются одинаково: нет тарифных уровней скорости и отдельной квоты API. Ответить 429 все же могут две вещи, обе с типом rate_limit_error. Различить их позволяет сообщение.

Баланс

Ваш баланс — это лимит плана на сегодня, который обновляется в 00:00 UTC, а после него — купленные кредиты. Чат и API списывают с одного и того же баланса.

Каждый запрос сначала резервирует свой лимит вывода: max_tokens или max_output_tokens на /v1/responses, 4,096, если вы не отправили ни того, ни другого. Когда ответ завершен, зарезервированная сумма заменяется тем, что запрос использовал. Если сумма не помещается в оставшийся баланс, запрос возвращает Quota exceeded до запуска модели.

Запросы, выполняемые одновременно, резервируют каждый свою сумму. Поэтому множество параллельных запросов с большим max_tokens может на время исчерпать баланс, даже если каждый ответ короткий. Меньший max_tokens резервирует меньше.

Защита от флуда

Защита от флуда допускает 120 запросов в минуту на аккаунт. Она считает аккаунт, а не ключ, по /v1/chat/completions, /v1/responses и /v1/messages вместе. Минута начинается с вашего первого запроса.

Запрос номер 121 в течение этой минуты возвращает Too many requests. Retry in <n>s. и ничего не стоит. Отклоненные запросы тоже считаются, поэтому клиент, который повторяет запрос без ожидания, остается отклоненным до конца минуты. Подождите <n> секунд, указанных в сообщении.

Параллельно отправленные запросы не отклоняются за параллельность. Они ждут в очереди и обрабатываются по очереди.

GET /v1/models и эндпоинты подсчета токенов не учитываются.

Подробнее о лимитах и балансе и о том, где посмотреть свой баланс и использование: Лимиты и баланс Keys & usage

Что повторять

Повторяйте запрос только тогда, когда тот же запрос может завершиться успешно. SDK OpenAI и Anthropic уже сами дважды повторяют ответы 429 и 5xx; чтобы изменить это, задайте max_retries (maxRetries в JavaScript).

Ошибка Повторять? Как
400, 404, 405, 413, 415, 422 Нет. Сначала исправьте запрос. Сообщение называет неверное поле, модель или ввод.
401 Нет. Используйте действительный ключ. Создайте или замените ключ на странице Keys & usage.
429 Too many requests Да, после ожидания. Подождите число секунд из сообщения, затем отправьте тот же запрос.
429 Quota exceeded Не в таком виде. Уменьшите max_tokens, дождитесь ежедневного сброса в 00:00 UTC или пополните кредит.
429 Shannon Coder call quota reached Да, в следующем окне. Окна начинаются каждые 4 часа от 00:00 UTC. Другая модель ответит сразу.
429 … temporarily busy Да. Подождите несколько секунд, а при каждой следующей попытке — дольше.
500, 502, 503 Да. Подождите 1 секунду, затем 2, 4 и 8. Остановитесь после нескольких попыток и сообщите id запроса.
504 Да. Отправьте его с stream, равным true: ограничение по времени действует для ответов без стриминга.

Цикл повторов, который следует этой таблице:

import re
import time

import openai
from openai import OpenAI

# max_retries=0: this loop does the retrying, the SDK does not add its own.
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.shannon-ai.com/v1", max_retries=0)


def create_with_retry(attempts=5, **request):
    for attempt in range(attempts):
        try:
            return client.chat.completions.create(**request)
        except openai.RateLimitError as error:
            text = str(error)
            flood = re.search(r"Retry in (\d+)s", text)
            if flood:
                time.sleep(int(flood.group(1)))   # flood protection: wait out the minute
            elif "temporarily busy" in text:
                time.sleep(2 ** attempt)
            else:
                raise                             # balance: a wait of seconds does not help
        except (openai.InternalServerError, openai.APIConnectionError):
            time.sleep(2 ** attempt)              # 1, 2, 4, 8 seconds
    raise RuntimeError("the request failed after all attempts")


response = create_with_retry(
    model="shannon-3",
    messages=[{"role": "user", "content": "Hello"}],
)
print(response.choices[0].message.content)

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

Поток имеет статус 200 с первого байта. Сбой после этого приходит как событие внутри потока: чанк с полем error на /v1/chat/completions, событие error на /v1/messages, событие response.failed или error на /v1/responses. Завершающие события потока все равно следуют. Считайте такой ответ неудачным и отправьте запрос снова, как при статусе 5xx.

Разговор, превышающий контекстное окно модели, сообщается именно так, с типом invalid_request_error и кодом context_length_exceeded. Сократите разговор, прежде чем отправлять его снова.

Точные фреймы описаны в разделе о стриминге. Потоковая передача

Id запросов

Каждый ответ, включая ошибки, имеет заголовок x-request-id. Это значение, которое вы отправили в собственном заголовке x-request-id, либо 12 шестнадцатеричных символов, если вы ничего не отправляли. Записывайте его в журнал и приводите, когда просите помощи по запросу.