Erros
Todo código nomeado que o gateway emite, agrupado pelo que você faz com ele.
Toda recusa nossa tem o mesmo corpo. Programe contra o codigo: ele é vocabulário estável. A mensagem é texto para pessoas e pode mudar sem aviso — e nunca revela detalhe interno.
{
"erro": {
"codigo": "escopo_insuficiente",
"mensagem": "Você não tem permissão para esta ação."
}
}Forma da requisição
Recusas decididas antes de qualquer chamada a provedor — o corpo, um cabeçalho ou um parâmetro não têm a forma que a rota exige. Nunca consomem orçamento nem cota, e repetir a mesma requisição dá exatamente o mesmo resultado.
| Código | Status | O que aconteceu | O que fazer |
|---|---|---|---|
model_ausente | 400 | O campo `model` está ausente ou não é texto. | Mande o identificador do modelo como string, igual à OpenAI. |
requisicao_invalida | 400 · 413 | Corpo malformado, tipo não suportado, ou acima do teto global de 1 MiB. O mesmo código nos dois casos: para quem integra, "grande demais" e "malformado" são a mesma recusa de forma — só o status HTTP muda. | Confira o JSON e o tamanho do corpo antes de reenviar. |
metadata_invalida | 400 | O cabeçalho `x-metadata` não é um objeto JSON de textos. | Serialize um objeto de pares texto→texto, sem números nem aninhamento. |
config_invalido | 400 | O `x-portkey-config` não existe nesta organização. | Use o id de uma config da própria org, ou remova o cabeçalho para cair no padrão da chave. |
input_invalido | 400 | Em embeddings: `input` ausente, string vazia, array vazio, item vazio, ou acima de 2048 itens. | Mande uma string não vazia ou um array de até 2048 strings não vazias. |
encoding_nao_suportado | 400 | Em embeddings: `encoding_format` diferente de `float`. O SDK oficial da OpenAI escolhe base64 por conta própria quando o chamador não pede formato nenhum. | Passe `encoding_format: "float"` explicitamente. |
operacao_nao_suportada | 400 | O provedor resolvido não tem adaptador para a operação pedida — hoje embeddings só sai por integrações OpenAI e OpenAI-compatíveis. | Roteie o modelo para uma integração que suporte a operação. |
variavel_invalida | 400 | Em prompts versionados: o campo `variables` veio e não é um objeto JSON. | Mande `variables` como objeto, ou omita o campo. |
corpo_invalido | 400 | No gateway MCP: o corpo não é JSON-RPC 2.0 válido. | Deixe o SDK de MCP montar a mensagem — o gateway não reescreve o envelope. |
corpo_grande_demais | 413 | Nos gateways MCP e A2A: corpo acima de 1 MiB. | Quebre a chamada, ou mande o conteúdo por referência em vez de embutido. |
notificacao_invalida | 400 | No webhook entrante de agente: o corpo não é uma notificação A2A (falta `id` ou `status.state` do objeto `Task`). Só o shape do protocolo entra: o que chega aqui é repassado ao webhook do cliente ASSINADO POR NÓS, e aceitar corpo arbitrário faria do gateway um relay de conteúdo anônimo com selo nosso. | Mande o objeto `Task` do protocolo — quem chama essa rota é o agente, não o cliente. |
notificacao_grande_demais | 413 | No webhook entrante de agente: corpo acima de 256 KiB (teto próprio, menor que o do proxy). | Uma notificação A2A é um `Task`; acima desse tamanho não é notificação, é upload. |
webhook_config_invalida | 200 (JSON-RPC) | No gateway A2A: `tasks/pushNotificationConfig/set` sem `params.taskId` ou sem `pushNotificationConfig.url`. Recusa NO PROTOCOLO (`code: -32602`), não no HTTP — um 400 sairia do JSON-RPC no meio de uma conversa JSON-RPC. | Mande o `taskId` e a URL do seu webhook no `set`. |
webhook_batch_nao_suportado | 200 (JSON-RPC) | No gateway A2A: QUALQUER lote JSON-RPC (um array no corpo) que contenha uma chamada `tasks/pushNotificationConfig/set|get` é recusado INTEIRO, mesmo que essa seja a ÚNICA chamada do lote — a mediação de webhook não sabe reescrever metade de um corpo que o cliente mandou como uma unidade, e um array de um item só ainda é um array. | Mande a configuração de push notification fora do lote, sozinha (um objeto JSON-RPC solto, não `[...]`). |
webhook_mediacao_indisponivel | 200 (JSON-RPC) | No gateway A2A: o operador do gateway não configurou a URL pública (`NUCLEO_URL_PUBLICA`), então não há endereço para registrar no agente — a mediação de push notifications fica indisponível. Misconfiguração do GATEWAY, não do seu pedido. | Avise o operador da plataforma; o resto do proxy A2A segue funcionando. |
parametro_invalido | 400 | Em `GET /v1/logs`: `limite` não é inteiro positivo, `desde`/`ate` não são datas válidas, ou o workspace não é um identificador válido. | Corrija o parâmetro de query indicado na mensagem. |
modo_invalido | 400 | Em `PUT /v1/privacy-mode`: um valor que não é `completo` nem `metadados`. É recusado explicitamente — nunca aceito em silêncio como o mais restritivo. | Mande um dos dois valores exatos. |
Autenticação
A credencial não foi apresentada, ou não resolve mais.
| Código | Status | O que aconteceu | O que fazer |
|---|---|---|---|
nao_autenticado | 401 | Credencial ausente ou inválida. Uma chave revogada ou rotacionada cai aqui, indistinguível de um segredo desconhecido. | Mande `Authorization: Bearer <chave>` com uma chave ativa. |
Autorização e portões da organização
A credencial é válida, mas a organização decidiu que esta chamada não passa. São os portões que a plataforma existe para aplicar — nunca uma falha de integração.
| Código | Status | O que aconteceu | O que fazer |
|---|---|---|---|
escopo_insuficiente | 403 | A chave não tem o escopo da rota — `completions.write` no data plane, `mcp.invoke` no gateway MCP, `logs.list` na trilha, `configs.read`/`configs.update` no modo de registro. | Emita uma chave com o escopo, no workspace certo. |
budget_esgotado | 403 | O orçamento do período acabou para o par (integração, workspace). | Espere a janela virar ou reveja o limite no console. |
modelo_nao_permitido | 403 | O modelo pedido não está liberado para esta organização. | Use um modelo do catálogo da org. |
workspace_nao_permitido | 403 | A chave pediu a trilha de um workspace que não é o dela. | Consulte a trilha com uma chave do próprio workspace. |
org_em_exclusao | 403 | A organização está na janela entre o pedido de exclusão e a execução. O corpo traz `agendadaEm`. | Cancele a exclusão no console antes da data agendada. |
Não encontrado
Um corpo só para "não existe" e para "existe, mas não é seu": quem varre referências nunca aprende o que existe do outro lado.
| Código | Status | O que aconteceu | O que fazer |
|---|---|---|---|
prompt_nao_encontrado | 404 | Referência inexistente, versão fora do range, label sem versão atribuída, ou prompt de outro workspace — os quatro respondem igual. | Confira a referência e o workspace da chave. |
servidor_mcp_nao_encontrado | 404 | Slug inexistente, ou existente e não provisionado para o workspace da chave — o mesmo corpo nos dois casos. | Provisione o servidor para o workspace no console. |
servidor_agent_nao_encontrado | 404 | No gateway A2A: slug de agente inexistente, ou existente e não provisionado para o workspace da chave — o mesmo corpo nos dois casos, no proxy e na descoberta do card. É o enforcement DURO do produto (o único que não depende de cooperação do cliente). | Provisione o agente para o workspace no console. |
nao_encontrado | 404 | No webhook entrante de agente (`POST /a2a/webhook/{token}`): token desconhecido, vencido ou de task já encerrada — o mesmo corpo para os três, porque essa superfície não é oráculo de nada. | Nada a fazer do lado de quem integra: o token é emitido e rotacionado por nós, por task, e expira com ela. |
Renderização de prompt
O prompt existe, a permissão está certa, mas o template não vira mensagem. Status 422: nada foi chamado no provedor.
| Código | Status | O que aconteceu | O que fazer |
|---|---|---|---|
partial_nao_encontrado | 422 | Um `{{>id}}` que não resolve, ou com sufixo inválido — partials só aceitam `@N` numérico. | Publique o partial, ou corrija a referência no template. |
partial_ciclico | 422 | Inclusão circular de partials, ou profundidade excedida. | Quebre o ciclo entre os partials incluídos. |
Taxa
Recusas de ritmo. São as únicas em que repetir a MESMA requisição depois costuma dar certo — com espera, nunca em laço apertado.
| Código | Status | O que aconteceu | O que fazer |
|---|---|---|---|
rate_limite_excedido | 429 | O par (integração, workspace) estourou um limite de taxa configurado. Um 429 do provedor é repassado com o corpo dele — olhe `x-origem-da-falha` para distinguir. | Recue com backoff; reveja o limite se for recorrente. |
rate_limit | 429 | Teto por IP da rota pública `GET /v1/openapi.json`. | Guarde o documento em cache em vez de buscá-lo a cada render. |
Guardrails
Conteúdo recusado por política. O status 446 fica de propósito fora da faixa que os SDKs compatíveis com OpenAI interpretam: nunca é confundido com sucesso parcial nem com erro do provedor.
| Código | Status | O que aconteceu | O que fazer |
|---|---|---|---|
guardrail_negou | 446 | Um guardrail bloqueante recusou o conteúdo, na entrada ou na saída. O corpo diz QUAL guardrail e QUAL check — nunca o conteúdo detectado. | Trate como recusa de política: mostre ao usuário, não repita a mesma requisição. |
ferramenta_nao_permitida | 200 (JSON-RPC) | No gateway MCP: ferramenta fora da allowlist da organização. A recusa vem NO PROTOCOLO (`code: -32603`), não no HTTP — derrubar a sessão de um cliente de SDK por política seria pior do que responder o que ele sabe ler. | Libere a ferramenta na allowlist, ou não a chame. |
skill_nao_permitida | 200 (JSON-RPC) | No gateway A2A: a mensagem DECLAROU uma skill (em `message.metadata.skillId` — convenção da Avalon, opt-in, não campo do protocolo) que está fora da allowlist do par agente×workspace. Recusa NO PROTOCOLO (`code: -32603`), pelo mesmo motivo do MCP. Mensagem que não declara skill nenhuma NÃO é filtrada por esta lista. | Libere a skill na allowlist do workspace, ou não a declare. |
webhook_url_invalida | 200 (JSON-RPC) | No gateway A2A: a URL de webhook que o cliente configurou não é alcançável por este gateway (mesma política de rede/SSRF do resto do produto). Recusa NO PROTOCOLO (`code: -32602`). A URL é validada de novo no instante da entrega — o DNS pode mudar depois da configuração. | Use um endereço https público (ou um host confiado no gateway) para receber as notificações. |
Plataforma
Falhas NOSSAS. Todas saem com `x-origem-da-falha: plataforma` — é o que separa um problema daqui de um erro repassado do provedor.
| Código | Status | O que aconteceu | O que fazer |
|---|---|---|---|
erro_interno | 500 | Falha nossa não classificada. | Guarde o `x-avalon-request-id` e abra o chamado com ele. |
motor_indisponivel | 502 | O motor de roteamento não roteou, ou não conseguiu conectar no alvo. É falha nossa, nunca do provedor. | Repita com backoff; se persistir, confira o `api_base` da integração. |
upstream_mcp_indisponivel | 502 | Rede, timeout ou 5xx do servidor MCP, e também a reconexão OAuth necessária. O corpo do upstream nunca é repassado (pode carregar credencial nossa). | Reautorize a integração MCP, ou repita depois. |
upstream_agent_indisponivel | 502 | Rede, timeout ou 5xx do agente A2A — ou um card que não declara endpoint JSON-RPC usável. O corpo do upstream nunca é repassado. Um erro A2A do próprio agente (`-32001 TaskNotFound`) NÃO cai aqui: é resposta legítima do protocolo e volta crua, dentro de um 200. | Repita com backoff; se persistir, confira a URL base e o agent card do agente no console. |
limites_indisponiveis | 503 | O contador de orçamento/taxa está inalcançável. Recusa deliberada: nunca liberar gasto com o controle cego. | Repita depois — a recusa some quando o contador volta. |
POST /v1/feedback
| Código | Status | O que aconteceu | O que fazer |
|---|---|---|---|
request_id_invalido | 400 | `request_id` ausente ou não é um UUID válido. | Mande o `x-avalon-request-id` da resposta que você quer avaliar. |
valor_invalido | 400 | `valor` ausente, não inteiro, ou fora do intervalo -10..10. | Mande um número inteiro entre -10 e 10. |
peso_invalido | 400 | `peso` presente e não é um número entre 0 e 1. | Omita o campo (peso 1 por padrão) ou mande um número entre 0 e 1. |
metadata_invalida | 400 | `metadata` presente e não é um objeto JSON de texto→texto, ou algum valor excede 128 caracteres. | Omita o campo, ou mande um objeto plano com valores de até 128 caracteres. |
nao_encontrado | 404 | `request_id` inexistente, ou de uma requisição de outro workspace — o mesmo corpo nos dois casos, para que quem varre ids não aprenda o que existe. | Confira o id e o workspace da chave que está avaliando. |