Xestión de erros
Unha solicitude que falla devolve un código de estado HTTP e un corpo JSON cun tipo de erro e unha mensaxe. Esta páxina lista todos os estados, mostra o corpo de erro de cada formato da API e indica que erros paga a pena reenviar.
Os SDK lanzan un obxecto de erro que leva o código de estado e os campos do corpo. Esta solicitude nomea un modelo que non existe:
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"}]
}' Devolve o estado 400 e este corpo:
{
"error": {
"type": "invalid_request_error",
"message": "unknown model: no-such-model"
}
} Corpo do erro
Hai dous corpos. /v1/messages responde no formato Anthropic; todos os demais endpoints responden no formato OpenAI. En ambos, os detalles están en error.type e error.message, así que un só lector serve para todos os endpoints.
{
"error": {
"type": "authentication_error",
"message": "Invalid API key",
"code": "invalid_api_key",
"param": null
}
} {
"type": "error",
"error": {
"type": "authentication_error",
"message": "Invalid API key"
}
} | Campo | Tipo | Descrición |
|---|---|---|
error.type | string | O tipo de erro. Consulta Tipos de erro máis abaixo. |
error.message | string | Unha frase para unha persoa. Os textos das táboas seguintes son estables salvo nas partes variables, mostradas como <id>, <n> ou …. |
error.code | string | null | Presente en algúns erros do formato OpenAI: invalid_api_key con 401, request_too_large con 413, context_length_exceeded cando unha conversa é demasiado longa, e null ou ausente nos demais casos. Decide primeiro polo estado e error.type e trata code como un extra. |
error.param | null | Presente nos mesmos erros que code. Sempre null. |
type | string | Só no formato Anthropic. Sempre error. |
Tipos de erro
| Tipo | Estados | Descrición |
|---|---|---|
invalid_request_error | 400, 413, 415, 422 | A propia solicitude é incorrecta: un campo, o corpo, o id do modelo ou unha entrada que o modelo non acepta. Cambia a solicitude antes de enviala de novo. |
authentication_error | 401 | A clave API falta, é descoñecida ou está revogada. |
not_found_error | 404 | A ruta non existe. |
rate_limit_error | 429 | O saldo non cobre a solicitude, a protección contra inundación detívoa ou o modelo está ocupado. A mensaxe indica cal é o caso. |
api_error | 500, 502, 503, 504 | A solicitude era correcta e o fallo está da nosa banda. Envíaa de novo. |
server_error | 500 | A solicitude era correcta e o fallo está da nosa banda. Envíaa de novo. |
Códigos de estado
| Estado | Tipo | Mensaxe | Cando |
|---|---|---|---|
400 | invalid_request_error | Failed to parse the request body as JSON: … | O corpo non é JSON válido. |
400 | invalid_request_error | unknown model: <id> | model non é un id publicado. En /v1/responses tamén cando falta model. |
400 | invalid_request_error | No user message provided | Niveis Shannon: a solicitude non contén texto de usuario. |
400 | invalid_request_error | <id> does not accept image input | Enviouse unha imaxe a un modelo open-weight alojado sen entrada de imaxe. |
400 | invalid_request_error | audio and video input are not supported by any hosted model | Enviouse unha parte de audio ou vídeo a un modelo open-weight alojado. |
400 | invalid_request_error | <id> does not accept response_format | Pediuse saída estruturada a un modelo open-weight alojado que non a ten. |
400 | invalid_request_error | <id> does not accept response_format json_schema; use json_object | Enviouse un esquema JSON a un modelo open-weight alojado que só acepta json_object. |
400 | invalid_request_error | unknown reasoning effort '<value>'; expected off, low, medium or high | O esforzo de razoamento non é un dos valores da lista. Modelos open-weight alojados. |
400 | invalid_request_error | count_tokens is available for the hosted open models; unknown model: <id> | Pediuse o reconto de tokens para un modelo que non é dos open-weight alojados. |
401 | authentication_error | Missing authentication | Non se enviou ningunha clave API. |
401 | authentication_error | Invalid API key | A clave é descoñecida, substituíuse por unha máis nova ou foi revogada. |
404 | not_found_error | Not Found | A ruta non existe, por exemplo /v1/embeddings. |
405 | api_error | Method Not Allowed | A ruta existe, pero non con este método HTTP. |
413 | invalid_request_error | Failed to buffer the request body: … | O corpo da solicitude é maior de 32 MiB. |
415 | invalid_request_error | Expected request with `Content-Type: application/json` | A cabeceira Content-Type falta ou non é application/json. |
422 | invalid_request_error | Failed to deserialize the JSON body into the target type: … | Falta un campo obrigatorio, como messages, ou un campo ten o tipo JSON incorrecto. |
429 | rate_limit_error | Quota exceeded. Upgrade your plan at shannon-ai.com/plan | O límite de saída da solicitude é maior que o que queda do teu saldo. |
429 | rate_limit_error | Too many requests. Retry in <n>s. | Protección contra inundación: máis de 120 solicitudes nun minuto na túa conta. <n> é o número de segundos ata que remata o minuto. |
429 | rate_limit_error | Shannon Coder call quota reached. Upgrade your plan at shannon-ai.com/plan | shannon-coder-1 en /v1/chat/completions e /v1/messages: usáronse as chamadas de Shannon Coder do teu plan para a xanela actual de 4 horas. |
429 | rate_limit_error | Shannon routes are temporarily busy. Please retry. | O modelo está ocupado neste momento. |
500 | server_error | The model backend failed to answer. Please retry. | O modelo non produciu unha resposta. |
500 | server_error | An internal error occurred. Please retry. | Un fallo interno mentres se preparaba a solicitude. |
502 | api_error | The model backend failed to answer. Please retry. | O modelo non produciu unha resposta. Familia Shannon 3 e modelos open-weight alojados. |
503 | api_error | Could not verify your quota right now. Please retry. | Non se puido ler o teu saldo neste momento. |
503 | api_error | token counting is temporarily unavailable for this model | O reconto de tokens non está dispoñible para este modelo neste momento. |
504 | api_error | upstream timed out | Un modelo open-weight alojado tardou máis que o límite de tempo dunha solicitude sen stream. |
As comprobacións execútanse nesta orde: clave API, corpo da solicitude, id do modelo, protección contra inundación, saldo. Unha solicitude cunha clave incorrecta e un corpo incorrecto devolve, polo tanto, 401. Unha solicitude rexeitada cun estado 4xx non se cobra.
Saldo e protección contra inundación
Todas as solicitudes se atenden por igual: non hai niveis de taxa nin unha cota de API separada. Aínda así, dúas cousas poden responder 429, ambas co tipo rate_limit_error. A mensaxe distingue unha da outra.
Saldo
O teu saldo é a cota do plan de hoxe, que se restablece ás 00:00 UTC, e despois dela o teu crédito adquirido. O chat e a API usan o mesmo saldo.
Cada solicitude reserva primeiro o seu límite de saída: max_tokens, ou max_output_tokens en /v1/responses, 4,096 se non envías ningún. Cando a resposta está completa, a cantidade reservada substitúese polo que usou a solicitude. Se a cantidade non cabe no saldo que queda, a solicitude devolve Quota exceeded antes de que o modelo comece.
As solicitudes que se executan á vez reservan cada unha a súa propia cantidade. Moitas solicitudes en paralelo cun max_tokens alto poden, polo tanto, esgotar o saldo por un momento, aínda que cada resposta sexa curta. Un max_tokens menor reserva menos.
Protección contra inundación
A protección contra inundación permite 120 solicitudes por minuto e conta. Conta a conta, non a clave, en /v1/chat/completions, /v1/responses e /v1/messages xuntos. O minuto comeza coa túa primeira solicitude.
A solicitude número 121 dentro dese minuto devolve Too many requests. Retry in <n>s. e non custa nada. As solicitudes rexeitadas tamén contan, así que un cliente que reenvía sen agardar segue rexeitado ata que remate o minuto. Agarda os <n> segundos da mensaxe.
As solicitudes enviadas en paralelo non se rexeitan por seren paralelas. Agardan na cola e respóndense por turnos.
GET /v1/models e os endpoints de reconto de tokens non se contan.
Máis sobre límites e saldo, e onde ver o teu propio saldo e uso: Límites e saldo Claves e uso
Que reintentar
Envía unha solicitude de novo só cando esa mesma solicitude pode ter éxito. Os SDK de OpenAI e Anthropic xa reintentan por si mesmos dúas veces as respostas 429 e 5xx; define max_retries (maxRetries en JavaScript) para cambialo.
| Erro | Enviar de novo? | Como |
|---|---|---|
400, 404, 405, 413, 415, 422 | Non. Corrixe primeiro a solicitude. | A mensaxe nomea o campo, o modelo ou a entrada que é incorrecta. |
401 | Non. Usa unha clave válida. | Crea ou substitúe a clave na páxina Claves e uso. |
429 Too many requests | Si, despois da espera. | Agarda o número de segundos da mensaxe e envía a mesma solicitude. |
429 Quota exceeded | Non tal como está. | Reduce max_tokens, agarda ao restablecemento diario ás 00:00 UTC ou engade crédito. |
429 Shannon Coder call quota reached | Si, na seguinte xanela. | As xanelas comezan cada 4 horas desde as 00:00 UTC. Outro modelo responde de inmediato. |
429 … temporarily busy | Si. | Agarda uns segundos e despois máis tempo en cada novo intento. |
500, 502, 503 | Si. | Agarda 1 segundo, despois 2, 4 e 8. Detente despois duns poucos intentos e informa do id da solicitude. |
504 | Si. | Envíaa con stream definido como true: o límite de tempo aplícase ás respostas sen stream. |
Un bucle de reintento que segue esta táboa:
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); Erros dentro dun stream
Un stream ten o estado 200 desde o seu primeiro byte. Un fallo posterior chega como un evento dentro do stream: un chunk cun membro error en /v1/chat/completions, un evento error en /v1/messages, un evento response.failed ou error en /v1/responses. Os eventos de peche do stream seguen chegando. Considera esa resposta como fallida e envía a solicitude de novo, como cun estado 5xx.
Unha conversa máis longa que a ventá de contexto do modelo infórmase deste xeito, co tipo invalid_request_error e o código context_length_exceeded. Acurta a conversa antes de enviala de novo.
Os frames exactos descríbense no apartado de streaming. Streaming
Ids de solicitude
Todas as respostas, erros incluídos, teñen unha cabeceira x-request-id. É o valor que enviaches na túa propia cabeceira x-request-id, ou 12 caracteres hexadecimais se non enviaches ningún. Rexístrao e cítao cando pidas axuda cunha solicitude.