Gestionare erori
O cerere care eșuează returnează un cod de stare HTTP și un corp JSON cu un tip de eroare și un mesaj. Această pagină listează fiecare stare, arată corpul de eroare al fiecărui format API și spune ce erori merită retrimise.
SDK-urile ridică un obiect de eroare care poartă codul de stare și câmpurile corpului. Această cerere indică un model care nu există:
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"}]
}' Returnează starea 400 și acest corp:
{
"error": {
"type": "invalid_request_error",
"message": "unknown model: no-such-model"
}
} Corpul erorii
Există două corpuri. /v1/messages răspunde în formatul Anthropic; fiecare alt endpoint răspunde în formatul OpenAI. În ambele, detaliile sunt în error.type și error.message, deci un singur cititor servește toate endpoint-urile.
{
"error": {
"type": "authentication_error",
"message": "Invalid API key",
"code": "invalid_api_key",
"param": null
}
} {
"type": "error",
"error": {
"type": "authentication_error",
"message": "Invalid API key"
}
} | Câmp | Tip | Descriere |
|---|---|---|
error.type | string | Felul erorii. Vezi Tipuri de erori mai jos. |
error.message | string | O propoziție pentru un om. Textele din tabelele de mai jos sunt stabile, cu excepția părților variabile, afișate ca <id>, <n> sau …. |
error.code | string | null | Prezent la unele erori în formatul OpenAI: invalid_api_key cu 401, request_too_large cu 413, context_length_exceeded când o conversație este prea lungă, altfel null sau absent. Decide mai întâi după stare și error.type și tratează code ca pe un extra. |
error.param | null | Prezent la aceleași erori ca code. Întotdeauna null. |
type | string | Doar în formatul Anthropic. Întotdeauna error. |
Tipuri de erori
| Tip | Stări | Descriere |
|---|---|---|
invalid_request_error | 400, 413, 415, 422 | Cererea în sine este greșită: un câmp, corpul, id-ul modelului sau o intrare pe care modelul nu o acceptă. Modifică cererea înainte să o trimiți din nou. |
authentication_error | 401 | Cheia API lipsește, este necunoscută sau revocată. |
not_found_error | 404 | Calea nu există. |
rate_limit_error | 429 | Soldul nu acoperă cererea, protecția anti-flood a oprit-o sau modelul este ocupat. Mesajul spune care este cazul. |
api_error | 500, 502, 503, 504 | Cererea era în regulă, iar eroarea este de partea noastră. Trimite-o din nou. |
server_error | 500 | Cererea era în regulă, iar eroarea este de partea noastră. Trimite-o din nou. |
Coduri de stare
| Stare | Tip | Mesaj | Când |
|---|---|---|---|
400 | invalid_request_error | Failed to parse the request body as JSON: … | Corpul nu este JSON valid. |
400 | invalid_request_error | unknown model: <id> | model nu este un id publicat. Pe /v1/responses, și când model lipsește. |
400 | invalid_request_error | No user message provided | Niveluri Shannon: cererea nu conține text de la utilizator. |
400 | invalid_request_error | <id> does not accept image input | O imagine a fost trimisă unui model open-weight găzduit care nu acceptă imagini la intrare. |
400 | invalid_request_error | audio and video input are not supported by any hosted model | O parte audio sau video a fost trimisă unui model open-weight găzduit. |
400 | invalid_request_error | <id> does not accept response_format | S-a cerut ieșire structurată de la un model open-weight găzduit care nu o are. |
400 | invalid_request_error | <id> does not accept response_format json_schema; use json_object | O schemă JSON a fost trimisă unui model open-weight găzduit care acceptă doar json_object. |
400 | invalid_request_error | unknown reasoning effort '<value>'; expected off, low, medium or high | Efortul de raționament nu este una dintre valorile listate. Modele open-weight găzduite. |
400 | invalid_request_error | count_tokens is available for the hosted open models; unknown model: <id> | S-a cerut numărarea token-urilor pentru un model din afara modelelor open-weight găzduite. |
401 | authentication_error | Missing authentication | Nu a fost trimisă nicio cheie API. |
401 | authentication_error | Invalid API key | Cheia este necunoscută, a fost înlocuită cu una mai nouă sau a fost revocată. |
404 | not_found_error | Not Found | Calea nu există, de exemplu /v1/embeddings. |
405 | api_error | Method Not Allowed | Calea există, dar nu cu această metodă HTTP. |
413 | invalid_request_error | Failed to buffer the request body: … | Corpul cererii este mai mare de 32 MiB. |
415 | invalid_request_error | Expected request with `Content-Type: application/json` | Header-ul Content-Type lipsește sau nu este application/json. |
422 | invalid_request_error | Failed to deserialize the JSON body into the target type: … | Lipsește un câmp obligatoriu, cum ar fi messages, sau un câmp are tipul JSON greșit. |
429 | rate_limit_error | Quota exceeded. Upgrade your plan at shannon-ai.com/plan | Limita de ieșire a cererii este mai mare decât ce a rămas din soldul tău. |
429 | rate_limit_error | Too many requests. Retry in <n>s. | Protecție anti-flood: mai mult de 120 de cereri într-un minut pe contul tău. <n> este numărul de secunde până la sfârșitul minutului. |
429 | rate_limit_error | Shannon Coder call quota reached. Upgrade your plan at shannon-ai.com/plan | shannon-coder-1 pe /v1/chat/completions și /v1/messages: apelurile Shannon Coder ale planului tău pentru fereastra curentă de 4 ore au fost consumate. |
429 | rate_limit_error | Shannon routes are temporarily busy. Please retry. | Modelul este ocupat în acest moment. |
500 | server_error | The model backend failed to answer. Please retry. | Modelul nu a produs un răspuns. |
500 | server_error | An internal error occurred. Please retry. | O eroare internă în timpul pregătirii cererii. |
502 | api_error | The model backend failed to answer. Please retry. | Modelul nu a produs un răspuns. Familia Shannon 3 și modelele open-weight găzduite. |
503 | api_error | Could not verify your quota right now. Please retry. | Soldul tău nu a putut fi citit în acest moment. |
503 | api_error | token counting is temporarily unavailable for this model | Numărarea token-urilor nu este disponibilă pentru acest model în acest moment. |
504 | api_error | upstream timed out | Un model open-weight găzduit a durat mai mult decât limita de timp a unei cereri fără streaming. |
Verificările rulează în această ordine: cheia API, corpul cererii, id-ul modelului, protecția anti-flood, soldul. O cerere cu o cheie greșită și un corp greșit returnează deci 401. O cerere refuzată cu o stare 4xx nu este taxată.
Sold și protecție anti-flood
Fiecare cerere este servită în mod egal: nu există niveluri de rată și nici o cotă API separată. Două lucruri pot totuși răspunde cu 429, ambele cu tipul rate_limit_error. Mesajul le deosebește.
Sold
Soldul tău este cota zilnică a planului de azi, care se resetează la 00:00 UTC, și după aceasta creditul tău achiziționat. Chatul și API-ul folosesc același sold.
Fiecare cerere rezervă mai întâi limita ei de ieșire: max_tokens sau max_output_tokens pe /v1/responses, 4,096 când nu trimiți niciuna. Când răspunsul este complet, suma rezervată este înlocuită cu ce a folosit cererea. Dacă suma nu încape în soldul rămas, cererea returnează Quota exceeded înainte ca modelul să înceapă.
Cererile care rulează în același timp rezervă fiecare suma ei. Multe cereri paralele cu un max_tokens mare pot deci epuiza soldul pentru o clipă, chiar dacă fiecare răspuns este scurt. Un max_tokens mai mic rezervă mai puțin.
Protecție anti-flood
Protecția anti-flood permite 120 de cereri pe minut pe cont. Numără contul, nu cheia, pe /v1/chat/completions, /v1/responses și /v1/messages la un loc. Minutul începe cu prima ta cerere.
Cererea cu numărul 121 din acel minut returnează Too many requests. Retry in <n>s. și nu costă nimic. Cererile refuzate se numără și ele, deci un client care retrimite fără să aștepte rămâne refuzat până se termină minutul. Așteaptă cele <n> secunde din mesaj.
Cererile trimise în paralel nu sunt refuzate pentru că sunt paralele. Ele așteaptă la coadă și primesc răspuns pe rând.
GET /v1/models și endpoint-urile de numărare a token-urilor nu sunt numărate.
Mai multe despre limite și sold și unde îți vezi propriul sold și propria utilizare: Limite și sold Chei și utilizare
Ce merită reîncercat
Retrimite o cerere doar când aceeași cerere poate reuși. SDK-urile OpenAI și Anthropic reîncearcă deja singure de două ori răspunsurile 429 și 5xx; setează max_retries (maxRetries în JavaScript) pentru a schimba asta.
| Eroare | Se retrimite? | Cum |
|---|---|---|
400, 404, 405, 413, 415, 422 | Nu. Corectează mai întâi cererea. | Mesajul indică câmpul, modelul sau intrarea care este greșită. |
401 | Nu. Folosește o cheie validă. | Creează sau înlocuiește cheia pe pagina Chei și utilizare. |
429 Too many requests | Da, după așteptare. | Așteaptă numărul de secunde din mesaj, apoi trimite aceeași cerere. |
429 Quota exceeded | Nu așa cum este. | Redu max_tokens, așteaptă resetarea zilnică la 00:00 UTC sau adaugă credit. |
429 Shannon Coder call quota reached | Da, în fereastra următoare. | Ferestrele încep la fiecare 4 ore de la 00:00 UTC. Un alt model răspunde imediat. |
429 … temporarily busy | Da. | Așteaptă câteva secunde, apoi mai mult la fiecare încercare ulterioară. |
500, 502, 503 | Da. | Așteaptă 1 secundă, apoi 2, 4 și 8. Oprește-te după câteva încercări și raportează id-ul cererii. |
504 | Da. | Trimite-o cu stream setat la true: limita de timp se aplică răspunsurilor fără streaming. |
O buclă de reîncercare care urmează acest tabel:
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); Erori în interiorul unui stream
Un stream are starea 200 de la primul octet. O eroare de după aceea sosește ca eveniment în interiorul stream-ului: un chunk cu un membru error pe /v1/chat/completions, un eveniment error pe /v1/messages, un eveniment response.failed sau error pe /v1/responses. Evenimentele de închidere ale stream-ului urmează totuși. Tratează un astfel de răspuns ca eșuat și retrimite cererea, ca la o stare 5xx.
O conversație mai lungă decât fereastra de context a modelului este raportată în acest mod, cu tipul invalid_request_error și codul context_length_exceeded. Scurtează conversația înainte să o trimiți din nou.
Cadrele exacte sunt descrise la streaming. Streaming
Id-uri de cerere
Fiecare răspuns, inclusiv erorile, are un header x-request-id. Este valoarea trimisă de tine în propriul header x-request-id sau 12 caractere hexazecimale dacă nu ai trimis niciuna. Înregistreaz-o în jurnal și menționeaz-o când ceri ajutor pentru o cerere.