Обработка на грешки
Заявка, която пропадне, връща 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 import OpenAI from "openai";
const client = new OpenAI({
apiKey: "YOUR_API_KEY",
baseURL: "https://api.shannon-ai.com/v1",
});
try {
await client.chat.completions.create({
model: "no-such-model",
messages: [{ role: "user", content: "Hello" }],
});
} catch (error) {
if (!(error instanceof OpenAI.APIError)) throw error;
console.log(error.status); // 400
console.log(error.type); // invalid_request_error
console.log(error.error.message); // unknown model: no-such-model
} curl -i https://api.shannon-ai.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "no-such-model",
"messages": [{"role": "user", "content": "Hello"}]
}' Тя връща статус 400 и това тяло:
{
"error": {
"type": "invalid_request_error",
"message": "unknown model: no-such-model"
}
} Тяло на грешката
Има две тела. /v1/messages отговаря във формата на Anthropic; всеки друг ендпоинт отговаря във формата на OpenAI. И в двата подробностите са в error.type и error.message, така че един четец обслужва всички ендпоинти.
{
"error": {
"type": "authentication_error",
"message": "Invalid API key",
"code": "invalid_api_key",
"param": null
}
} {
"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 и ендпоинтите за броене на токени не се броят.
Повече за лимитите и баланса и къде да видите собствения си баланс и използване: Ограничения и баланс 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) import OpenAI from "openai";
// maxRetries: 0 — this loop does the retrying, the SDK does not add its own.
const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.shannon-ai.com/v1", maxRetries: 0 });
const sleep = (seconds) => new Promise((resolve) => setTimeout(resolve, seconds * 1000));
async function createWithRetry(request, attempts = 5) {
for (let attempt = 0; attempt < attempts; attempt++) {
try {
return await client.chat.completions.create(request);
} catch (error) {
const text = String(error.message);
const flood = text.match(/Retry in (\d+)s/);
if (error.status === 429 && flood) {
await sleep(Number(flood[1])); // flood protection: wait out the minute
} else if (error.status === 429 && text.includes("temporarily busy")) {
await sleep(2 ** attempt);
} else if (error.status >= 500 || error instanceof OpenAI.APIConnectionError) {
await sleep(2 ** attempt); // 1, 2, 4, 8 seconds
} else {
throw error; // wrong request, wrong key or balance
}
}
}
throw new Error("the request failed after all attempts");
}
const response = await createWithRetry({
model: "shannon-3",
messages: [{ role: "user", content: "Hello" }],
});
console.log(response.choices[0].message.content); Грешки вътре в стрийм
Стриймът има статус 200 от първия си байт. Неуспех след това пристига като събитие вътре в стрийма: chunk с член 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 шестнадесетични знака, ако не сте изпратили. Записвайте го в логове и го цитирайте, когато искате помощ за заявка.