Ir para o conteúdo

15 · Erros, recusas e solução de problemas

Uma requisição pode falhar de algumas maneiras, e cada uma pede uma resposta diferente: um campo corrigido, uma chave, um outro par de escolhas, um arquivo menor, uma espera. Este capítulo traz todo erro que o serviço devolve, toda recusa com o motivo de existir, as exceções que o cliente Python levanta para eles, e as falhas de integração que as equipes mais encontram, a mais comum primeiro.

Erros

Todo erro é um corpo JSON com um code e uma message, e o status HTTP diz como responder a ele: 400 pede um campo corrigido, 401 uma chave, 403 uma permissão que o seu plano tenha, 409 uma outra combinação de escolhas, 410 uma nova resolução, 413 um arquivo menor ou uma segunda requisição, 429 uma espera, 503 a mesma requisição de novo daqui a pouco. Gerado a partir das próprias classes de erro do serviço:

Status Código Quando
400 invalid_request Violação do esquema: modo desconhecido, chave de configuração desconhecida, operando de outro modo.
400 signup_link_invalid Um link expirado, já usado ou desconhecido.
401 unauthenticated Nenhuma chave, um cabeçalho malformado ou uma chave que não é verificada.
403 google_signin_refused Um token de ID que falha numa verificação, ou um endereço do Google não verificado. Nomeia a verificação.
403 not_entitled A chave é válida e não tem a permissão de que esta requisição precisa.
403 not_in_tier O tenant da chave está num plano que não inclui isto.
403 package_not_entitled O feed de pacotes, pedido por uma credencial sem a permissão packages.
403 provider_host_not_allowed Um endpoint de modelo indicado por quem chamou, que o worker não pode chamar.
403 test_key_restricted Uma chave qls_test_ pediu algo que só uma chave de produção pode ter.
409 contract_error Uma requisição de cobrança que o estado deste tenant não permite: billing_not_available, subscription_exists ou brl_price_not_eligible. HTTP 409, e o código é o slug.
409 idempotency_key_reused A mesma chave de idempotência, enviada com uma requisição diferente.
409 refused Uma requisição bem formada cuja combinação de escolhas não consegue responder à pergunta.
409 signup_address_refused Um endereço descartável ou que não recebe e-mail.
410 artifact_purged O artefato existiu e os seus bytes não existem mais.
413 input_too_large Quem chamou enviou, ou declarou, mais bytes do que o seu limite permite.
413 payload_too_large Quem chamou pediu numa resposta mais do que uma resposta pode carregar.
422 generation_unusable O modelo respondeu, e o que ele respondeu não pode ser usado.
429 quota_exhausted Um limite da chave se esgotou, ou um teto de concorrência está cheio.
429 signup_rate_limited Cadastro ou login além de um limite por endereço, por IP ou por domínio.
502 provider_error O provedor de modelo do cliente recusou ou falhou numa chamada feita em seu nome.
503 billing_unavailable Uma rota de cobrança num host sem chaves do Stripe.
503 queue_saturated Uma classe de fila tem mais trabalho pendente do que o seu teto.
503 service_unavailable Um armazenamento sem o qual esta requisição não roda está inacessível neste momento.

Um 429 que se resolve sozinho traz Retry-After. 429 quota_exhausted não se resolve sozinho: ele nomeia o medidor, o que foi usado, o teto e quando ele se renova (capítulo 16).

Recusas

Uma recusa é um 409 refused com um slug em refusal: uma requisição bem formada cuja combinação de escolhas não consegue responder à pergunta que faz. Cada uma é recusada pelo nome, porque a alternativa, em todos os casos, é uma execução que responde a uma pergunta que ninguém fez e que parece exatamente uma que alguém fez. Uma recusa antes de o job entrar na fila não custa nada; uma quando o job roda é um job que terminou com a recusa como resposta.

Recusa Recusada Por quê
enumerate_needs_checkable_profile antes de o job entrar na fila Uma contagem dos contextos que quebram uma política só vale a pena relatar quando a execução que a produz é uma que um auditor pode verificar. Nenhum dos perfis oferece certificado, então a contagem seria infalsificável. Promovê-la em silêncio seria pior: quem chamou pediu uma execução barata e seria cobrado por uma prova.
enumerate_outside_guardrail antes de o job entrar na fila Há uma única obrigação cujos contextos enumerar, e só esse modo nomeia uma.
batch_repair_needs_certificate antes de o job entrar na fila Uma linha deve um reparo quando espera SAT ou STALL e não dispensou o cinto de segurança -- SAT e STALL igualmente, porque não conseguir descartar um desfecho exige a mesma resposta que provar que ele é alcançável. Tal linha é avaliada pelos invariantes do reparo, então uma execução que não pode produzir um não pode respondê-la. Se rodasse, o gate relataria a ausência de um reparo que ninguém procurou: uma linha cujo veredito bateu exatamente ainda falha, e o build fica vermelho numa política correta.
batch_certificate_required_unsatisfiable_config antes de o job entrar na fila Tal linha é cumprida por uma refutação que um terceiro pode VERIFICAR, e uma config que define certificate_detail none não deixa nada para verificar, assim como um que define enable_phase2 false, que não deixa nenhuma refutação derivada.
sequence_needs_chain antes de o job entrar na fila A pergunta cumulativa sobre um único passo é a pergunta de um único turno, e respondê-la em silêncio deixaria quem chama acreditar que perguntou outra coisa.
pins_belong_in_the_table antes de o job entrar na fila Os pins de uma propriedade pertencem à sua linha da tabela, onde são revisados com ela. Na linha de comando eles valeriam para todas as perguntas ao mesmo tempo, que é a falha de excesso de pins que a tabela existe para tornar visível. Uma enumeração propõe pins em vez de recebê-los, e a busca de pins é o que decide de quais pins uma obrigação precisa.
suggested_table_not_promoted antes de o job entrar na fila Esta tabela ainda carrega os marcadores que uma enumeração deixa. Uma linha candidata é uma proposta: o id nomeia uma pergunta enquanto algum registro se referir a ela, e a expectativa é a afirmação sendo verificada, e nenhum dos dois é algo derivável da política. Rodar a tabela com eles em branco seria promover uma proposta a compromisso ao enviá-la, que é a etapa de revisão que toda esta camada existe para tornar barata.
forest_profile_keys_are_sealed antes de o job entrar na fila As chaves do perfil forest são o que uma resposta neste modo significa, e este modo não roda com elas editadas -- exceto oracle_unsat_admissible, que uma requisição pode desligar para aceitar apenas refutações derivadas. Os desfechos importam mais: com a Fase 3 e a Fase 4 ambas desligadas, um stall não significa nada. Escolha o perfil ou escolha as chaves; neste modo são a mesma escolha.
root_bound_needs_closure antes de o job entrar na fila max_roots > 1 exige enable_phase3; só o desfecho por fechamento enumera uma variedade. Um pedido de várias raízes sem ele não pode ser atendido, e devolver uma mesmo assim relataria errado o resultado.
emission_needs_rails_config quando o job roda Uma resposta sem fase não distingue uma verificação na entrada de uma verificação na saída; uma propriedade da mensagem inteira sobre um fluxo em streaming é uma prova sobre uma mensagem que nunca existe em tempo de execução.
bad_context_phase antes de o job entrar na fila Uma fase que os rails não sabem nomear registraria um fio que a política nunca menciona, e o fixaria num valor que nada lê. O context de uma tabela de propriedades tem a mesma forma e segue a mesma regra.
forest_region_needs_default quando o job roda Fixo e livre fazem perguntas diferentes -- uma é sobre os vizinhos de um registro, a outra sobre uma população inteira -- e uma ferramenta que escolhesse uma estaria escolhendo a pergunta do autor por ele.
forest_feature_needs_domain quando o job roda Uma feature sem limites gera contraexemplos fora de tudo o que o modelo jamais verá: um saldo negativo, uma idade de quatrocentos anos. Essas descobertas são verdadeiras sobre o modelo e inúteis para o seu dono.
forest_domains_not_confirmed quando o job roda Limites inferidos de uma amostra são fatos sobre a amostra. Se uma conta pode ser negativa ou se uma idade é fixa é uma afirmação sobre o mundo, e uma pessoa a confirma antes que um veredito se apoie nela.
forest_anchor_outside_domain quando o job roda Uma região construída em torno de um ponto impossível pergunta sobre vizinhos impossíveis, e um grupo one-hot com dois membros definidos, ou nenhum, não é um registro.
forest_region_needs_anchor quando o job roda Uma propriedade de robustez é robusta em torno de um registro, e uma feature fixa ou uma bola é fixada nele ou centrada nele. Sem o registro a pergunta não tem sujeito.
forest_unsupported_construct quando o job roda Divisões por igualdade e por pertencimento a conjunto, pré-processamento dentro do grafo, uma transformação não monotônica, ou uma chave do Treelite que o dump 4.x fixado não escreve: cada um é recusado pelo nome em vez de aproximado.
forest_model_mismatch quando o job roda Uma tabela que traz um model_sha256 que não é o deste modelo é recusada, porque uma tabela revisada contra um modelo não é evidência sobre outro.
obligation_not_on_that_rail quando o job roda Recusada em vez de respondida, nomeando os rails em que ela é consultada. Uma verificação colocada na ponta errada do pipeline não é o controle que aparenta, e responder à pergunta sem qualificação a relataria como um.
pin_names_the_obligation quando o job roda A obrigação é fixada em 0 para perguntar se a ação pode disparar sem ela, e um pin condicionante na mesma variável é escrito depois no mesmo fio. O pin vence, então a execução responde à pergunta oposta sob o id daquela linha -- e o veredito, o certificado e a entrada de auditoria permanecem todos coerentes sobre a pergunta que acham que foi feita, então nada a jusante consegue perceber.
seatbelt_waiver_missing antes de o job entrar na fila Dispensar o cinto de segurança é a única edição da tabela que deixa verde uma linha vermelha sem tocar na política, então ela precisa deixar uma frase dizendo por quê: uma varredura que não pode falhar não é evidência. Numa linha UNSAT não há nada a dispensar -- nenhum reparo é produzido -- então o campo pareceria uma restrição que a execução respeita enquanto não respeita nada, e passaria a ter peso no dia em que a expectativa da linha mudasse. max_sds ao lado de uma dispensa é recusado pelo mesmo motivo.
ir_version_unsupported quando o job roda Recusado antes de qualquer leitura estrutural, nomeando a janela. Acima dela, o leitor está atrás do tradutor que o escreveu.
ir_version_retired quando o job roda Recusado antes de qualquer leitura estrutural, nomeando a janela. Acima dela, o leitor está atrás do tradutor que o escreveu; abaixo dela, o registro está aposentado e a mensagem nomeia a versão do tradutor com que reemiti-lo.
session_steps_mismatch quando o job roda Recusado nomeando as duas profundidades. Um registro desdobrado em dois passos não pode responder a uma pergunta sobre três, e responder mesmo assim relataria uma prova sobre um circuito que ninguém descreveu.
session_steps_unrecorded quando o job roda Um registro 1.0.0 não declara profundidade nenhuma, então uma pergunta que nomeia uma é recusada como não registrada; perguntada sem ela, é respondida na profundidade em que ele foi construído e o relatório o diz.
phase_not_recorded quando o job roda Um registro não carrega rails, então a obrigação não pode ser colocada em nenhuma das pontas do pipeline.
colang_version_ambiguous quando o job roda O dialeto em que uma política está decide o que cada linha dela significa. Nada dela é interpretado, e a recusa nomeia as linhas que discordam.
colang2_construct_unsupported quando o job roda Recusado pelo nome com a sua linha, e nenhum veredito é dado. O cone é todo fluxo que registra a ação, todo fluxo que constrói uma porta do seu guard, e toda linha não lida que poderia invocá-la -- nomeando-a, ou uma linha execute, await, start, send, run, activate ou bot; uma construção fora dele é listada como aviso e o veredito se mantém, porque não pode mudar a resposta.
colang_unread_in_cone quando o job roda A mesma regra que para o Colang 2: uma linha não lida é uma aresta ausente, e uma aresta ausente pode fazer uma política parecer segura sem ser. Uma linha num fluxo fora do cone é um aviso e o veredito se mantém; uma linha fora de todo fluxo está em todo cone.
graph_schema_invalid quando o job roda O export é o que é verificado, então um que o leitor não consegue sujeitar ao seu esquema é recusado antes de qualquer compilação, nomeando a primeira violação.
graph_catalogue_mismatch quando o job roda Recusado nomeando a ferramenta. Uma ferramenta que o catálogo não declara não tem verificação, nem texto de confirmação, nem classificação, então nada que um veredito dissesse sobre ela seria sobre a ferramenta que roda.
graph_recursion quando o job roda Subgrafos são incorporados a cada uso, e um que contém a si mesmo não tem profundidade até onde incorporar.
graph_too_large quando o job roda Subgrafos são incorporados a cada uso, então um grafo é tão grande quanto fica depois de incorporado: um subgrafo usado duas vezes em cada um de vinte níveis vira um milhão de nós a partir de quarenta declarados. Recusado acima de 4096 nós incorporados, nomeando o nó que passou do limite.

As exceções do cliente

O cliente Python transforma cada erro numa exceção que traz o que você precisa para agir:

Exceção Quando O que traz
LicenceRequired nenhuma chave de API, ou nenhuma licença ativada nesta máquina nomeia stalwart licence activate e onde obter uma chave
SelectorUnavailableError um plano ou uma verificação de ferramenta sem runtime e sem router_url qual dos dois configurar
PersonalDataError dados pessoais numa requisição destinada aos nossos servidores; nada foi enviado .findings: o tipo de cada ocorrência e onde ela está, nunca o seu valor
ConfigurationError uma URL base inválida, ou um runtime que não está lá
AuthenticationError 401
NotEntitledError 403 .entitlement: a permissão que falta à chave
RefusedError 409 refused .slug, .explanation, .stage
QuotaExceededError 429 num medidor mensal; nunca tentado de novo .meter, .used, .limit, .resets_at
ConcurrencyLimitError, RateLimitError um 429 que se resolve sozinho, levantado depois das novas tentativas .current, .limit
InputTooLargeError 413 .limit_bytes
JobFailedError um job que terminou failed .cause, .stderr_tail
DigestMismatch um download que não confere com o seu digest
StreamError um stream que não pode ser retomado
ServiceError 5xx, depois das novas tentativas .request_id

Um veredito nunca é uma exceção: SAT e STALL são respostas (capítulo 6). O cliente tenta de novo leituras, planos e verificações numa conexão que caiu, num tempo esgotado, num 5xx e num 429 que se resolve sozinho, respeitando o Retry-After. Uma resolução é enviada sob uma chave de idempotência que o cliente deriva, então uma nova tentativa de envio é um único job.

O pacote de agentes levanta os seus próprios erros, cada um dizendo o que mudar nas palavras do agent.yaml (capítulo 30).

Solução de problemas

As falhas que as equipes mais encontram, a mais comum primeiro.

  1. Um stream chega todo de uma vez, no fim. Um proxy entre você e nós está acumulando a resposta: uma resolução de dois segundos parece igual com ou sem acúmulo, então isso só aparece nas longas. Desligue o acúmulo para o caminho, ou deixe o cliente passar a consultar, o que ele faz sozinho depois de dois streams que falharam (capítulo 9). O stalwart doctor verifica se o streaming passa.
  2. SelectorUnavailableError num plano ou numa verificação de ferramenta. Planos e verificações rodam na sua própria máquina: ative a licença uma vez (stalwart licence activate), ou nomeie o seu roteador enterprise com QLS_ROUTER_URL. O nosso serviço hospedado não responde a nenhum dos dois (capítulo 38).
  3. LicenceRequired. Nada no pacote funciona sem uma chave e uma licença ativada, exceto ativá-la, o stalwart doctor e conferir um certificado. Defina QLS_API_KEY e rode stalwart licence activate uma vez na máquina.
  4. PersonalDataError. Algo destinado aos nossos servidores, como a descrição de um catálogo, uma planilha de regras ou um prompt, contém um endereço de e-mail, um número de telefone, um número de cartão ou outro identificador, e nada foi enviado. O erro nomeia o tipo e o lugar; tire o valor, ou liste os seus próprios identificadores com own_identifiers= se a ocorrência for sua para enviar.
  5. Um veredito SAT lido como uma falha, ou uma tabela reprovada lida como aprovada. Um achado é um job bem-sucedido: decida pelo verdict.status e pelo hard_failures de uma tabela, nunca pelo status HTTP ou pelo código de saída (capítulo 11).
  6. 409 refused com colang_unread_in_cone. O compilador não conseguiu ler uma linha que a pergunta alcança, e um veredito sobre ela não significaria nada. A recusa nomeia a linha (capítulo 6).
  7. 403 not_entitled ou not_in_tier. Falta a permissão à sua chave, ou a funcionalidade ao seu plano. O corpo diz qual; o capítulo 40 diz o que cada plano inclui.
  8. 429 quota_exhausted. Um medidor mensal se esgotou. O corpo o nomeia e dá a data da renovação; a página Usage do console mostra cada medidor contra o seu teto.
  9. 410 artifact_purged. O artefato foi apagado no fim da sua janela de retenção. O seu digest e o seu registro continuam; rode o job de novo para obtê-lo outra vez (capítulo 16).
  10. 409 idempotency_key_reused. A mesma chave de idempotência foi enviada com uma requisição diferente. Use uma chave nova para uma requisição diferente; a mesma chave com a mesma requisição devolve o job existente.

Duas falhas que dizem pouco, de propósito

  • A falha de login do console é uma página com uma frase, seja qual for a causa: um link expirado, um endereço desconhecido, uma chave revogada, uma chave de teste. Distingui-las diria a quem está tentando adivinhar qual parte do palpite manter (capítulo 5).
  • O painel Test Request da referência da API só envia uma requisição para o host que serviu a página. Um servidor editado no painel para apontar para outro lugar é recusado pela política de segurança da página, e o painel não diz nada sobre o porquê (capítulo 18).

Os limites

  • Um erro diz o que falhou e o que mudar; ele não diz o que a execução teria encontrado.
  • Uma recusa é sobre a combinação que você pediu, não sobre a sua política.