Erros e limites
Códigos de erro da GetVibe API: 401 (chave), 402 (saldo), 403 (IP), 429 (limite de requisições). Como lidar com erros e repetir tentativas com recuo exponencial.
Os erros produzidos pelo GetVibe em /v1/* têm um envelope JSON com error.message, error.type e error.code. Não dependa do texto da mensagem nem dos headers de serviços de terceiros como contrato.
Formato de erro
{
"error": {
"message": "insufficient balance",
"type": "insufficient_quota",
"code": 402,
"request_id": "8d4b6b3a-..."
}
}Códigos de resposta
| Parâmetro | Tipo | Descrição |
|---|---|---|
401 | authentication_error / 401 | Chave ausente ou malformada, ou a chave está desativada. Não tente novamente até que as credenciais sejam corrigidas. |
402 | insufficient_quota / 402 | Não há saldo ou limite disponível: esperar não resolve. Um 402 nunca contém Retry-After e não deve ser repetido: faça uma recarga ou aguarde a redefinição da janela da assinatura. |
403 | permission_error or policy type / 403 | O IP, o modelo ou a política não permite a solicitação. Não tente novamente sem alterar a solicitação ou as configurações. |
429 | rate_limit_exceeded, inflight_client_cap or rate_limit_error / 429 | Seu limite de solicitações, seu limite de concorrência, uma reserva de saldo mantida brevemente pelas suas próprias solicitações concorrentes (causa reserved_in_flight) ou um limite do fornecedor. Tente novamente somente após Retry-After; um 429 nunca significa que seu saldo se esgotou. |
410 | media_endpoint_retired / media_endpoint_retired | Somente /v1/images/edits, /v1/video/generations e /v1/videos (descontinuados). Não tente novamente; mude para /api/media/generate. /v1/images/generations é atendido. |
413 | invalid_request_error / 413 | Somente a API de arquivos: o arquivo excede 50 MiB. Reduza o arquivo e crie uma nova solicitação. |
503 | overloaded / 503 | Sobrecarga global da edge. Tente novamente após Retry-After: 2. Outros erros 503 podem não permitir novas tentativas sem alterar o modelo ou a solicitação. |
Erros de requisição (400, 413, 422): códigos e correções
Todo erro de requisição inclui um error.code estável da tabela abaixo, error.param com o campo ao qual se refere (null quando o modelo não especifica um) e um link para a linha correspondente no final de error.message — o Codex e outras CLIs mostram apenas a mensagem, por isso o link é incluído nela.
| error.code | error.param | O que fazer |
|---|---|---|
unsupported_parameter | nome do campo | O modelo ou canal selecionado não aceita este parâmetro. Remova-o da requisição (no Codex/IDEs, da configuração) e tente novamente. |
invalid_parameter_value | nome do campo | O parâmetro está presente, mas seu valor não é permitido para este modelo: por exemplo, temperature diferente de 1 com o raciocínio ativado, max_tokens acima do máximo ou effort "none" quando o raciocínio não pode ser desativado. Corrija o valor conforme indicado na mensagem. |
missing_parameter | nome do campo | Um campo obrigatório está ausente ou vazio. Adicione-o. |
invalid_tool_schema | tools[].function.* | Uma definição de ferramenta foi rejeitada: os nomes só podem usar letras latinas, dígitos, "_" e "-"; parameters deve ser um JSON Schema cuja raiz seja type: "object". Ou escolha outra variante do modelo. |
tool_choice_unsupported | tool_choice | O modelo não oferece suporte à escolha forçada de ferramenta. Envie tool_choice "auto" ou "none". |
invalid_tool_history | messages / input | O histórico contém uma chamada de ferramenta sem resultado. Adicione o resultado com o mesmo id ou remova a chamada junto com seu resultado ao reduzir o histórico. |
invalid_image | — | Não foi possível ler a imagem. Envie um arquivo PNG, JPEG, WebP ou GIF completo (BMP, TIFF, AVIF e SVG não são aceitos). |
unsupported_input_modality | — | O modelo não aceita esse tipo de anexo (PDF, áudio, vídeo, imagens). Remova-o ou escolha um modelo cuja entrada no catálogo liste esse tipo de entrada. |
conversation_state_unreadable | — | O raciocínio no histórico foi criado por outro canal. A requisição é válida; tente novamente e, se o erro se repetir, inicie uma nova conversa. |
invalid_json | — | O corpo da requisição não é JSON ou chegou truncado. Para conversas muito longas com imagens, inicie uma nova conversa ou compacte o histórico. |
request_too_large | — | A requisição é muito grande. Reduza os anexos ou o histórico. |
request_rejected_by_channel | — | O canal do modelo recusou a requisição sem informar um motivo; a requisição em si provavelmente é válida. Tente novamente; se a recusa se repetir, escolha outra variante do modelo (o sufixo após os dois-pontos) ou o modelo sem sufixo. Se isso não ajudar, entre em contato com o suporte e informe o request_id. |
model_not_available_on_route | — | A rota não está configurada para este modelo. Escolha outro modelo ou variante. |
context_length_exceeded | messages / input / prompt | A requisição não cabe na janela de contexto. Compacte o histórico (no Codex: /compact) ou escolha um modelo com uma janela maior. |
content_moderation | — | A requisição ou a resposta foi bloqueada pelo filtro de conteúdo do provedor. Reformule-a ou escolha outro modelo. |
invalid_request | — | A causa não foi reconhecida. Confira a requisição na referência da API; se ela estiver correta, entre em contato com o suporte e informe o request_id da resposta. |
Cabeçalhos de resposta
| Parâmetro | Tipo | Descrição |
|---|---|---|
x-pv-cost-rub | string | Estimativa de custo em rublos com base no melhor esforço. Em streams, x-pv-cost-rub fica disponível quando a estimativa de entrada é conhecida; pv_cost_rub no evento final de uso exige x-pv-cost: 1. O histórico de uso contém o débito real. |
x-pv-generation-id | string | ID do registro do histórico de uso (GET /v1/generations/{id}). Retornado somente para solicitações de chat/completions sem streaming. |
x-pv-dropped-params | string | Parâmetros de solicitação separados por vírgulas que a rota selecionada não aceita e que, portanto, não foram enviados ao modelo (por exemplo, temperature,top_p). Presentes somente quando algo foi realmente retido, tanto nas respostas quanto nos erros. Nunca descartamos um parâmetro silenciosamente: sem esse cabeçalho, tudo o que você enviou chegou ao modelo sem alterações. |
Retry-After | integer | Segundos de espera. A borda define esse valor para limite de taxa 429, concorrência 429 (5), sobrecarga global 503 (2) e alguns 402 transitórios. Não é presumido para todo 429/503. |
Erros antes e depois do início da resposta
Uma transmissão lenta (stream: true) recebe 200 e : pv-keepalive comentários após 5 segundos de silêncio, para que a conexão não pareça inativa; uma solicitação longa sem transmissão recebe 200 e espaços em branco após o primeiro token. A partir desse momento, o status não pode mudar e um erro chega no corpo. Se o cliente alternar para outro fornecedor após um erro HTTP, envie x-pv-honest-errors: 1 (ou peça ao suporte para ativá-lo para a conta): nesse caso, não haverá keepalive nem um 200 antecipado antes do primeiro byte da resposta, e toda falha será um status HTTP comum com um corpo JSON. O custo é um socket silencioso até o primeiro token; o tempo limite do cabeçalho precisa cobrir esse período.
Um erro após o início da resposta é um único evento terminal: para chat event: error com {"error":{message,type,code,status},"choices":[{"finish_reason":"error"}]} seguido por data: [DONE]; para /v1/responses event: response.failed contendo o mesmo error; para /v1/messages, o event: error da Anthropic. code é a causa identificável pela máquina e status é o status HTTP que o erro teria antes do início da resposta.
stream: true), x-pv-generation-id não é retornado porque o faturamento é concluído após o término do stream. Revise o histórico de solicitações via GET /v1/generations.Limites de taxa e concorrência
Ambos os limites dependem do saldo atual da conta e se aplicam a todas as suas chaves de API em conjunto. A faixa é recalculada automaticamente: adicione saldo e o limite aumenta; se o saldo cair abaixo de um limiar, a faixa diminui. Não há limite de tokens por minuto (TPM).
| Saldo a partir de | Requisições por minuto (RPM) | Requisições simultâneas |
|---|---|---|
| 0 $ | 300 | 10 |
| 1 $ | 1 100 | 50 |
| 2 $ | 6 600 | 300 |
| 4 $ | 19 800 | 900 |
| 12 $ | 44 000 | 2 000 |
| Parâmetro | Tipo | Descrição |
|---|---|---|
429 rate_limit_exceeded | RPM | A conta enviou tantas requisições nos últimos 60 segundos (uma janela deslizante) quanto sua faixa permite. Retry-After é o número de segundos até que uma vaga na janela seja liberada (pelo menos 1); x-ratelimit-limit-requests é o seu RPM atual. Corpo: error.cause = key_rate_limited, error.details = { enforced_by: "getvibe", limit, unit: "requests_per_minute", retry_after_seconds }. |
429 inflight_client_cap | concurrency | Já há tantas requisições em execução quanto a faixa permite. Uma requisição ocupa sua vaga até ser concluída; um stream a ocupa até seu último evento. Retry-After: 5. Corpo: error.cause = account_concurrency_limited, error.details = { enforced_by: "getvibe", limit, unit: "parallel_requests", retry_after_seconds: 5 }. |
Personal limit | RPM | Se a conta tiver um limite de requisições personalizado, ele só poderá reduzir o RPM da faixa, nunca aumentá-lo. |
503 overloaded | service | Não é o seu limite, mas uma proteção do serviço: Retry-After: 2 indica o limite global de todas as contas; Retry-After: 1 significa que um servidor está ocupado. Tente novamente após a pausa. |
429 from a provider | upstream | error.cause = supplier_rate_limited significa que o provedor do modelo limitou a requisição e que seu próprio limite não foi esgotado; channel_rate_limited é o limite compartilhado de um canal do provedor (Retry-After: 10, nada foi enviado). |
Tentando novamente as solicitações
Para uma resposta que pode ser repetida, use primeiro Retry-After, se presente. Sem o cabeçalho, não trate nenhum 429 ou 503 como repetível automaticamente: verifique o status HTTP e o error.type público, corrija a causa que não pode ser repetida e use backoff limitado somente para um erro transitório.
import time, requests
def call_with_retry(url, headers, payload, max_retries=5):
for attempt in range(max_retries):
r = requests.post(url, headers=headers, json=payload)
if r.status_code == 429:
# honor Retry-After, otherwise exponential backoff
wait = int(r.headers.get("Retry-After", 2 ** attempt))
time.sleep(wait)
continue
return r
return r