Quando algo dá errado

Consultar um erro

#Cole o erro

Leia os erros nesta ordem: status HTTP, depois error.type, depois error.code. O status sempre tem significado; type diz quem rejeitou a chamada; code só é estável para erros gerados pelo próprio gateway.

#Como tratar cada caso

  1. 1

    Decida pelo status

    402 significa recarregar, 403 significa escopo da chave, 429 significa aguardar, 5xx significa tentar de novo. Esta camada nunca mente e nunca muda.

  2. 2

    Verifique error.type

    xiaoxiang_error é nosso. Qualquer outro — openai_error, claude_error, gemini_error — é o corpo do próprio provedor, encaminhado sem alteração.

  3. 3

    Depois leia error.code

    Só decida pelo code em xiaoxiang_error. Os códigos do upstream pertencem ao provedor e podem mudar sem aviso.

Nem toda falha tem corpo JSON

Rejeições por limite de taxa e corpos grandes demais são interrompidos só com a linha de status. Um parser que presume que response.json() sempre funciona vai lançar uma exceção no caminho de erro em vez de tratá-lo.
Envelopes de erro

Cinco formatos chegam ao seu cliente. Trate os cinco — os três últimos são os que as integrações costumam esquecer.

Erro do gateway

O próprio gateway rejeitou a chamada — autenticação, cota, roteamento, formato da requisição.

http
{
  "error": {
    "message": "insufficient account balance, please top up to continue (request id: 20260910...)",
    "type": "xiaoxiang_error",
    "code": "insufficient_user_quota"
  }
}

Erro do upstream, repassado

O provedor respondeu com o próprio erro. O corpo é encaminhado sem alterações, então type e code são os do provedor.

http
{
  "error": {
    "message": "This model's maximum context length is 128000 tokens.",
    "type": "invalid_request_error",
    "code": "context_length_exceeded"
  }
}

Rejeição por verificação prévia

A idempotência e algumas outras verificações anteriores ao relay respondem antes de o envelope do relay existir. Formato plano, code em maiúsculas.

http
{
  "code": "IDEMPOTENCY_IN_PROGRESS",
  "error": "a request with this Idempotency-Key is still processing"
}

Rejeição de tarefa assíncrona

Todo endpoint de tarefa — vídeo, tarefa de imagem, música, 3D — informa falhas no próprio formato plano. Não há objeto error aninhado aqui, então um parser escrito para /v1/chat/completions lê null.

http
{
  "code": "task_not_exist",
  "message": "task does not exist",
  "data": null
}

Só status, corpo vazio

Rejeições por limite de taxa e corpos de requisição grandes demais são interrompidos apenas com o status.

http
HTTP/1.1 429 Too Many Requests
Retry-After: 20
Content-Length: 0
Cabeçalhos de resposta

Registre o ID da requisição em toda resposta, não só nas falhas. É o identificador pelo qual o suporte rastreia uma chamada, e é a diferença entre uma resposta em cinco minutos e um dia de suposições.

CabeçalhoEnviado quandoO que fazer com ele
X-Oneapi-Request-IdToda resposta, de sucesso ou de erro.Registre-o junto ao seu próprio trace id. O suporte responde aos chamados com base neste valor, e o mesmo id é anexado às mensagens de erro do gateway.
Retry-AfterEm 429, e em 409 enquanto uma Idempotency-Key ainda está em processamento.Aguarde pelo menos esse número de segundos. É a única indicação de backoff que o gateway envia.
X-Idempotent-ReplayedUma resposta armazenada é reproduzida para uma Idempotency-Key repetida.true significa que nenhum trabalho novo foi executado e nada foi cobrado de novo — trate o corpo como o resultado original.
X-Idempotency-SealedA resposta original não pode ser reproduzida com segurança (por exemplo, um stream ou um corpo grande demais).Pare de tentar com essa chave. Em vez disso, faça a conciliação pelo endpoint da tarefa ou pelos seus próprios registros.
log-the-request-id.ts
const response = await fetch(url, init);
const requestId = response.headers.get("X-Oneapi-Request-Id");

if (!response.ok) {
  // Bodies are absent on 429 and 413 — never assume JSON here.
  const detail = await response.text();
  logger.error({ status: response.status, requestId, detail });
  throw new GatewayError(response.status, requestId, detail);
}

#Tabela de códigos de erro

Erros gerados pelo próprio gateway, sempre com type "xiaoxiang_error". Duas linhas compartilham o status 429 e significam coisas opostas — leia o code antes de fazer backoff.

HTTPCódigoSignificadoO que fazerRepetir?
401nenhumBearer token ausente, malformado, excluído ou desativado. Esta camada não define code — verifique pelo status.Verifique o cabeçalho Authorization e o estado da chave em Console → Chaves de API.não
401signature_requiredA chave tem assinatura de requisições ativada e a requisição não tem X-Timestamp, X-Nonce ou X-Signature.Assine todas as requisições feitas com esta chave (Autenticação e chaves → Assinatura de requisições) ou desative a assinatura na chave.não
401signature_expiredX-Timestamp não está em segundos Unix de 10 dígitos ou difere em mais de 5 minutos do horário do servidor. A resposta traz X-Server-Timestamp.Corrija o relógio do cliente pela diferença de X-Server-Timestamp e assine de novo com um novo nonce.sim
401signature_invalidX-Signature não corresponde ao segredo de assinatura da chave, ou X-Nonce está malformado.Assine timestamp, nonce, método e caminho (sem query string), unidos por quebras de linha, com o segredo atual de Console → Chaves de API.não
401signature_replayedEste X-Nonce já foi usado com esta chave nos últimos 10 minutos.Gere um nonce aleatório novo para cada requisição, inclusive nas novas tentativas.sim
403access_deniedO IP de origem está fora da lista de IPs permitidos da chave.Adicione o endereço de saída em Console → Chaves de API ou remova a lista de permissões das chaves sem IP fixo.não
403nenhumConta suspensa, ou a chave não tem permissão para usar este modelo ou canal.Verifique primeiro a lista de modelos permitidos da chave; se ela não tiver restrições, abra um chamado — a própria conta está bloqueada.não
400unsupported_endpointO modelo existe, mas não atende a este caminho. A mensagem lista os endpoints que ele atende.Mova a chamada para um endpoint da lista — modelos de tarefa de imagem não respondem em /v1/chat/completions.não
400read_request_body_failedNão foi possível ler o corpo da requisição — upload truncado, Content-Type errado ou um stream que terminou antes da hora.Envie um corpo completo com o Content-Type correspondente. Reenviar a mesma requisição quebrada falha do mesmo jeito.não
402insufficient_user_quotaO saldo da carteira não cobre o valor pré-reservado para esta chamada.Recarregue em Console → Carteira e tente novamente.não
429insufficient_user_quotaO limite de gastos diário da conta foi atingido. Mesmo status da limitação de taxa, significado oposto — backoff não resolve.Aumente ou remova o limite nas configurações da conta, ou retome amanhã. Decida pelo code, não apenas pelo 429.não
429nenhumLimite de RPM/RPD por chave ou proteção de concorrência. O corpo vem vazio; Retry-After informa a espera.Aguarde Retry-After segundos e tente novamente com backoff exponencial e jitter.sim
413read_request_body_failedO corpo da requisição excede o tamanho aceito. O limite da camada de transporte interrompe com corpo vazio.Reduza o payload — envie arquivos por /v1/media/upload-policy e mande a URL em vez de Base64.não
422invalid_requestNenhum canal oferece essa intenção de mídia para o modelo — por exemplo, imagem para vídeo em uma rota só de texto para vídeo.Confira na ficha do modelo as intenções suportadas e troque de modelo ou de intenção.não
503model_not_foundNome de modelo desconhecido, ou nenhum canal saudável o atende no momento. Atenção ao status: um modelo desconhecido retorna 503, não 404.Confira o nome em /v1/models e tente novamente — o failover geralmente encontra um canal saudável na próxima tentativa.sim
500sensitive_words_detectedO prompt foi barrado pelo filtro de conteúdo antes de sair do gateway.Altere o prompt. Tentar de novo com o mesmo texto sempre falha.não
500count_token_failedO gateway não conseguiu estimar os tokens para a precificação, geralmente por causa de um array de mensagens malformado.Valide o array messages; se estiver bem formado, tente novamente e abra um chamado com o ID da requisição.sim
500invalid_requestNão foi possível interpretar a requisição em um formato aceito por este endpoint. Atenção ao status — um corpo que o gateway não consegue ler é reportado como 500, não 400.Valide o JSON com a referência do endpoint antes de tentar novamente.não
502do_request_failedO provedor estava inacessível ou retornou uma falha que o gateway não conseguiu contornar com failover.Tente novamente com backoff — a próxima tentativa geralmente cai em outro canal.sim
504do_request_failedO provedor não respondeu dentro do prazo do gateway.Tente novamente com backoff; prompts longos e provedores sobrecarregados estouram o tempo limite com mais frequência.sim
499do_request_failedSeu cliente fechou a conexão antes de a resposta chegar — geralmente o próprio timeout HTTP disparando no meio do stream.Aumente o timeout de leitura do cliente. Gerações longas levam minutos, não o padrão da maioria das bibliotecas HTTP.não
Erros da proteção de idempotência

Estes vêm da proteção contra repetição que fica antes do relay, por isso usam o formato plano {code, error} com code em maiúsculas em vez do envelope da OpenAI.

HTTPCódigoSignificadoO que fazerRepetir?
400IDEMPOTENCY_STREAM_UNSUPPORTEDIdempotency-Key foi enviada em uma requisição de streaming.Remova o cabeçalho nas chamadas de streaming ou defina stream:false quando precisar de proteção contra repetição.não
400IDEMPOTENCY_BODY_UNREADABLENão foi possível gerar o hash do corpo para o registro de idempotência.Envie um corpo JSON ou multipart normal — corpos chunked que não podem ser armazenados em buffer são rejeitados.não
409IDEMPOTENCY_PAYLOAD_CONFLICTEsta chave já foi usada com outro corpo, caminho ou query.Gere uma nova chave. Uma chave identifica uma requisição exata, não um ciclo de novas tentativas.não
409IDEMPOTENCY_IN_PROGRESSA primeira requisição com esta chave ainda está em execução.Aguarde o Retry-After (2s) e tente novamente com a mesma chave — você receberá a resposta original.sim
409IDEMPOTENCY_RESULT_UNREPLAYABLEA requisição original terminou, mas a resposta foi selada e não pode ser reproduzida.Não reenvie às cegas. Faça primeiro a conciliação pelo endpoint da tarefa ou pelos seus próprios registros.não
503IDEMPOTENCY_UNAVAILABLEO registro de idempotência está indisponível, então a proteção falha fechada em vez de arriscar uma cobrança dupla.Tente novamente com backoff — a requisição não foi executada.sim

Como funcionam as chaves de idempotência →

Erros de tarefas assíncronas

Os endpoints de vídeo, tarefa de imagem, música e 3D respondem com o próprio formato plano — {code, message, data} — tanto no envio quanto na consulta e no cancelamento. Uma peculiaridade a considerar: consultar um id de tarefa desconhecido retorna 400; cancelar, 404.

HTTPCódigoSignificadoO que fazerRepetir?
400task_not_existConsultar ou fazer remix de um id de tarefa que não existe ou pertence a outra conta. Atenção ao status — consultar uma tarefa desconhecida retorna 400, enquanto cancelar uma retorna 404.Persista o task_id no momento do envio e consulte com exatamente esse valor.não
400invalid_requestFalta um campo obrigatório — prompt em um remix, task_id em uma consulta.Corrija o corpo ou o caminho antes de tentar novamente.não
400task_channel_disableUma tarefa derivada (remix, extensão) fica vinculada ao canal da tarefa original, e esse canal agora está desativado.Envie uma tarefa nova em vez de derivar da antiga.não
400invalid_source_taskA tarefa de origem é do tipo errado para esta operação — por exemplo, um id de vídeo passado para uma continuação 3D.Verifique se o id de origem veio da mesma família de recursos.não
404task_not_existCancelamento de um id de tarefa que não existe ou não é seu.Não há nada para cancelar — considere que já não existe.não
409task_not_cancellableA tarefa já chegou a um estado final, então não há nada para cancelar.Consulte mais uma vez e use o resultado pelo qual você já pagou.não
501task_cancel_not_supportedO provedor por trás desta tarefa não oferece API de cancelamento. A maioria não oferece — cancelar é a exceção, não a regra.Deixe a tarefa terminar. Projete a UI para que o cancelamento seja de melhor esforço, não uma garantia.não
502cancel_task_failedO provedor estava inacessível durante o cancelamento. A tarefa não foi alterada.Tente mais uma vez e, se falhar, deixe a tarefa terminar.sim

Ciclo de vida das tarefas assíncronas →

Ainda com problemas?

Envie para nós o ID da requisição ou a mensagem de erro e vamos investigar.