Перейти до вмісту
Обробка помилок

Обробка помилок

Запит, що завершується помилкою, повертає код статусу 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 Зображення надіслано до хостованої open-weight моделі без підтримки вхідних зображень.
400 invalid_request_error audio and video input are not supported by any hosted model Аудіо- або відеочастину надіслано до хостованої open-weight моделі.
400 invalid_request_error <id> does not accept response_format Структурований вивід запитано в хостованої open-weight моделі, що його не має.
400 invalid_request_error <id> does not accept response_format json_schema; use json_object JSON-схему надіслано до хостованої open-weight моделі, що приймає лише json_object.
400 invalid_request_error unknown reasoning effort '<value>'; expected off, low, medium or high Зусилля міркування не є одним із перелічених значень. Хостовані open-weight моделі.
400 invalid_request_error count_tokens is available for the hosted open models; unknown model: <id> Підрахунок токенів запитано для моделі поза хостованими open-weight моделями.
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 і хостовані open-weight моделі.
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 Хостована open-weight модель відповідала довше за обмеження часу для запиту без стрімінгу.

Перевірки виконуються в такому порядку: 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 та ендпоінти підрахунку токенів не рахуються.

Більше про ліміти й баланс і де побачити власний баланс та використання: Ліміти та баланс Ключі та використання

Що повторювати

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

Помилка Надсилати знову? Як
400, 404, 405, 413, 415, 422 Ні. Спершу виправте запит. Повідомлення називає поле, модель або вхід, що неправильні.
401 Ні. Використайте чинний ключ. Створіть або замініть ключ на сторінці «Ключі та використання».
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 шістнадцяткових символів, якщо ви нічого не надсилали. Логуйте його та наводьте, коли просите допомоги із запитом.