Ir para o conteúdo
Tratamento de erros

Tratamento de erros

Uma requisição que falha retorna um código de status HTTP e um corpo JSON com um tipo de erro e uma mensagem. Esta página lista todos os status, mostra o corpo de erro de cada formato de API e diz quais erros vale a pena enviar de novo.

Os SDKs levantam um objeto de erro que traz o código de status e os campos do corpo. Esta requisição indica um modelo que não 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

Ela retorna o status 400 e este corpo:

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

Corpo do erro

Há dois corpos. /v1/messages responde no formato Anthropic; todos os outros endpoints respondem no formato OpenAI. Nos dois, os detalhes estão em error.type e error.message, então um único leitor serve a todos os endpoints.

401 Formato OpenAI
{
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key",
    "code": "invalid_api_key",
    "param": null
  }
}
401 Formato Anthropic
{
  "type": "error",
  "error": {
    "type": "authentication_error",
    "message": "Invalid API key"
  }
}
Campo Tipo Descrição
error.type string O tipo de erro. Veja Tipos de erro abaixo.
error.message string Uma frase para uma pessoa. Os textos nas tabelas abaixo são estáveis, exceto nas partes variáveis, mostradas como <id>, <n> ou ….
error.code string | null Presente em alguns erros do formato OpenAI: invalid_api_key com 401, request_too_large com 413, context_length_exceeded quando uma conversa é longa demais; nos demais casos, null ou ausente. Decida primeiro pelo status e por error.type e trate code como um extra.
error.param null Presente nos mesmos erros que code. Sempre null.
type string Somente no formato Anthropic. Sempre error.

Tipos de erro

Tipo Status Descrição
invalid_request_error 400, 413, 415, 422 A própria requisição está errada: um campo, o corpo, o id do modelo ou uma entrada que o modelo não aceita. Altere a requisição antes de enviá-la de novo.
authentication_error 401 A chave de API está ausente, é desconhecida ou foi revogada.
not_found_error 404 O caminho não existe.
rate_limit_error 429 O saldo não cobre a requisição, a proteção contra flood a bloqueou, ou o modelo está ocupado. A mensagem diz qual.
api_error 500, 502, 503, 504 A requisição estava correta e a falha é do nosso lado. Envie-a de novo.
server_error 500 A requisição estava correta e a falha é do nosso lado. Envie-a de novo.

Códigos de status

Status Tipo Mensagem Quando
400 invalid_request_error Failed to parse the request body as JSON: … O corpo não é um JSON válido.
400 invalid_request_error unknown model: <id> model não é um id publicado. Em /v1/responses, também quando model está ausente.
400 invalid_request_error No user message provided Níveis Shannon: a requisição não contém texto de usuário.
400 invalid_request_error <id> does not accept image input Uma imagem foi enviada a um modelo open-weight hospedado sem entrada de imagem.
400 invalid_request_error audio and video input are not supported by any hosted model Uma parte de áudio ou vídeo foi enviada a um modelo open-weight hospedado.
400 invalid_request_error <id> does not accept response_format Saída estruturada foi pedida a um modelo open-weight hospedado que não a tem.
400 invalid_request_error <id> does not accept response_format json_schema; use json_object Um JSON schema foi enviado a um modelo open-weight hospedado que aceita apenas json_object.
400 invalid_request_error unknown reasoning effort '<value>'; expected off, low, medium or high O esforço de raciocínio não é um dos valores listados. Modelos open-weight hospedados.
400 invalid_request_error count_tokens is available for the hosted open models; unknown model: <id> A contagem de tokens foi pedida para um modelo fora dos modelos open-weight hospedados.
401 authentication_error Missing authentication Nenhuma chave de API foi enviada.
401 authentication_error Invalid API key A chave é desconhecida, foi substituída por uma mais nova ou foi revogada.
404 not_found_error Not Found O caminho não existe, por exemplo /v1/embeddings.
405 api_error Method Not Allowed O caminho existe, mas não com este método HTTP.
413 invalid_request_error Failed to buffer the request body: … O corpo da requisição é maior que 32 MiB.
415 invalid_request_error Expected request with `Content-Type: application/json` O header Content-Type está ausente ou não é application/json.
422 invalid_request_error Failed to deserialize the JSON body into the target type: … Falta um campo obrigatório, como messages, ou um campo tem o tipo JSON errado.
429 rate_limit_error Quota exceeded. Upgrade your plan at shannon-ai.com/plan O limite de saída da requisição é maior do que o que resta do seu saldo.
429 rate_limit_error Too many requests. Retry in <n>s. Proteção contra flood: mais de 120 requisições em um minuto na sua conta. <n> é o número de segundos até o fim do minuto.
429 rate_limit_error Shannon Coder call quota reached. Upgrade your plan at shannon-ai.com/plan shannon-coder-1 em /v1/chat/completions e /v1/messages: as chamadas do Shannon Coder do seu plano para a janela atual de 4 horas foram esgotadas.
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 não produziu uma resposta.
500 server_error An internal error occurred. Please retry. Uma falha interna enquanto a requisição era preparada.
502 api_error The model backend failed to answer. Please retry. O modelo não produziu uma resposta. Família Shannon 3 e modelos open-weight hospedados.
503 api_error Could not verify your quota right now. Please retry. Seu saldo não pôde ser lido neste momento.
503 api_error token counting is temporarily unavailable for this model A contagem de tokens não está disponível para este modelo neste momento.
504 api_error upstream timed out Um modelo open-weight hospedado demorou mais que o limite de tempo de uma requisição sem streaming.

As verificações são feitas nesta ordem: chave de API, corpo da requisição, id do modelo, proteção contra flood, saldo. Uma requisição com chave errada e corpo errado, portanto, retorna 401. Uma requisição recusada com um status 4xx não é cobrada.

Saldo e proteção contra flood

Todas as requisições são atendidas igualmente: não há faixas de limite de taxa nem cota de API separada. Mesmo assim, duas coisas podem responder 429, ambas com o tipo rate_limit_error. A mensagem as distingue.

Saldo

Seu saldo é a cota do plano de hoje, que é renovada às 00:00 UTC, e depois dela os seus créditos comprados. O chat e a API usam o mesmo saldo.

Cada requisição reserva primeiro o seu limite de saída: max_tokens, ou max_output_tokens em /v1/responses, 4,096 quando você não envia nenhum dos dois. Quando a resposta termina, a quantia reservada é substituída pelo que a requisição usou. Se a quantia não couber no saldo restante, a requisição retorna Quota exceeded antes de o modelo começar.

Requisições simultâneas reservam, cada uma, a sua própria quantia. Muitas requisições em paralelo com um max_tokens alto podem, portanto, esgotar o saldo por um momento, mesmo que cada resposta seja curta. Um max_tokens menor reserva menos.

Proteção contra flood

A proteção contra flood permite 120 requisições por minuto por conta. Ela conta a conta, não a chave, em /v1/chat/completions, /v1/responses e /v1/messages juntos. O minuto começa com a sua primeira requisição.

A requisição de número 121 dentro desse minuto retorna Too many requests. Retry in <n>s. e não custa nada. Requisições recusadas também contam, então um cliente que reenvia sem esperar continua recusado até o fim do minuto. Espere os <n> segundos indicados na mensagem.

Requisições enviadas em paralelo não são recusadas por serem paralelas. Elas esperam em fila e são respondidas em ordem.

GET /v1/models e os endpoints de contagem de tokens não são contados.

Mais sobre limites e saldo, e onde ver seu próprio saldo e uso: Limites e saldo Chaves e uso

O que tentar de novo

Envie uma requisição de novo somente quando a mesma requisição puder ter sucesso. Os SDKs da OpenAI e da Anthropic já repetem por conta própria duas vezes as respostas 429 e 5xx; defina max_retries (maxRetries em JavaScript) para mudar isso.

Erro Enviar de novo? Como
400, 404, 405, 413, 415, 422 Não. Corrija a requisição primeiro. A mensagem indica o campo, o modelo ou a entrada que está errada.
401 Não. Use uma chave válida. Crie ou substitua a chave na página Chaves e uso.
429 Too many requests Sim, depois da espera. Espere o número de segundos indicado na mensagem e envie a mesma requisição.
429 Quota exceeded Não como está. Reduza max_tokens, aguarde a renovação diária às 00:00 UTC ou adicione créditos.
429 Shannon Coder call quota reached Sim, na próxima janela. As janelas começam a cada 4 horas a partir das 00:00 UTC. Outro modelo responde imediatamente.
429 … temporarily busy Sim. Espere alguns segundos e, a cada nova tentativa, espere mais.
500, 502, 503 Sim. Espere 1 segundo, depois 2, 4 e 8. Pare após algumas tentativas e informe o id da requisição.
504 Sim. Envie-a com stream definido como true: o limite de tempo vale para respostas sem streaming.

Um loop de repetição que segue esta tabela:

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)

Erros dentro de um stream

Um stream tem status 200 desde o primeiro byte. Uma falha depois disso chega como um evento dentro do stream: um chunk com um membro error em /v1/chat/completions, um evento error em /v1/messages, um evento response.failed ou error em /v1/responses. Os eventos finais do stream ainda vêm em seguida. Trate essa resposta como falha e envie a requisição de novo, como para um status 5xx.

Uma conversa mais longa que a janela de contexto do modelo é informada desta forma, com o tipo invalid_request_error e o código context_length_exceeded. Reduza a conversa antes de enviá-la de novo.

Os frames exatos são descritos junto com o streaming. Streaming

Ids de requisição

Toda resposta, inclusive as de erro, tem um header x-request-id. É o valor que você enviou no seu próprio header x-request-id, ou 12 caracteres hexadecimais quando você não enviou nenhum. Registre-o em log e cite-o ao pedir ajuda com uma requisição.