Pular para conteúdo

Catálogo técnico de erros

O projeto distingue exceções Python, respostas HTTP e resultados de integração. Eles não são intercambiáveis: uma StubResponse(success=False) é um retorno controlado; um batchItemFailures instrui SQS a repetir; HANDOFF_PENDING entrega o caso a um humano. Comece pelo evento e pela camada em que a falha apareceu, não apenas pela mensagem final ao cliente.

Fontes: src/core/errors.py, src/core/application/process_message_use_case.py, src/core/application/confirm_action.py, src/orchestrator/app.py, src/webhook_handler/app.py, src/emulator/app.py e adapters em src/core/integrations/. Logs abaixo usam nomes reais; exemplos usam dados fictícios.

Exceções de domínio e aplicação

Erro Causa/sintoma Log esperado ou ponto de observação Retry? Ação recomendada e escalonamento
DomainError Invariante inválida, como alterar campo imutável de Session Exceção no chamador; pode aparecer em process_immediate_turn_failed SQS pode repetir se escapar Corrigir consumidor; não forçar dados persistidos
IllegalStateTransitionError Session.transition_to() recebe par fora de LEGAL_TRANSITIONS Campos from_state/to_state; force_handoff_blocked_by_state no fallback terminal Não é defeito de rede; repetição sem mudança tende a falhar Conferir máquina de estados, origem da ação e concorrência
InvalidAgentCodeError Código s não permitido para aquele agente llm_failure_handoff Sem retry semântico do código Handoff llm_invalid_json; revisar prompt e tabela de códigos
LLMResponseParseError Texto antes de JSON, chaves desbalanceadas, JSON malformado, s ausente/string/bool llm_response_parse_retry, llm_response_repair_success ou llm_response_repair_failed Uma chamada de reparo do formato Se reparo falhar, handoff llm_invalid_json; guardar exemplo sanitizado para regressão
ApplicationError em action mapping/invocador Enum/campo inválido ou agente sem builder/modelo llm_failure_handoff quando capturada no loop Não repete automaticamente como rede Motivo salvo llm_invalid_json; verificar contrato retornado
ApplicationError de dispatch DEBOUNCE_QUEUE_URL ausente Falha do webhook no dispatch Resolver configuração antes de repetir Conferir env e recurso SAM; não houve processamento downstream garantido
MissingRequiredFieldError Classe declarada para ausência de campo de serviço Sem uso/raise encontrado em src/ atual Não aplicável como fluxo ativo Consultar validação real em action mapping/catálogo; não atribuir esse erro a todo campo ausente
ContextPackageNotFoundError Classe declarada para package inexistente Sem uso/raise encontrado em src/ atual Não aplicável como fluxo ativo KnowledgeBaseRepository.get_package() retorna None; consultar fluxo de contexto atual
_TurnSupersededError Turno perdeu atualidade/posse antes de efeito final Resultado superseded, eventos do orchestrator Normalmente conclui receipt antigo; novo turno prossegue Comportamento esperado de latest-message-wins; não é handoff por erro

Docstrings não substituem o fluxo atual

LLMResponseParseError descreve handoff no comentário da classe, mas o fluxo atual tenta reparar o formato primeiro. Duas classes de erros de campos/contexto continuam declaradas sem uso no runtime. O fallback _handle_llm_failure() classifica toda IntegrationError como llm_timeout, e outros erros capturados de aplicação/contrato como llm_invalid_json; o nome do motivo não é diagnóstico suficiente.

Exemplos mínimos do parser:

{"s":1}Resposta válida.
Olá! {"s":1}Resposta inválida: texto antes do JSON.
{"s":"1"}Resposta inválida: código é string.
{"s":true}Resposta inválida: booleano não é código inteiro.

Whitespace antes do objeto é permitido. O parser reconhece aspas e escapes ao contar chaves. O reparo não autoriza o agente a mudar fatos ou executar ações fora do contrato; veja resposta dos agentes.

OpenAI e geração de resumo

Erro Causa/sintoma Log Retry? Ação e handoff
LLMTimeoutError APITimeoutError esgota loop do wrapper llm_timeoutllm_failure_handoff 1 + LLM_RETRY_MAX chamadas do wrapper; SDK também pode repetir Verificar tempo total/modelo; handoff llm_timeout
LLMProviderError, 401/403 Chave ou permissão inválida llm_4xx com status/modelo Wrapper falha imediatamente Corrigir chave/permissão; motivo registrado também llm_timeout
LLMProviderError, 400 Modelo/reasoning/request incompatível llm_4xx Sem retry do wrapper Conferir settings resolvidas e payload Responses
LLMProviderError, 429 Limite/cota do provider llm_4xx Sem retry do wrapper Conferir limite na conta; não aumentar retry indiscriminadamente
LLMProviderError, 5xx esgotado Instabilidade do serviço llm_5xxllm_failure_handoff Loop do wrapper Investigar recorrência; handoff llm_timeout
Exceção SDK fora das capturadas Por exemplo conexão não convertida em timeout/status Pode chegar a process_immediate_turn_failed Handler pede retry SQS Investigar classe real; não assumir que todo erro vira IntegrationError
Resumo com IntegrationError Provider falhou ao produzir resumo summary_llm_failed Provider aplica sua política; resumo usa fallback Continua com objeto mínimo e histórico
Resumo não parseável Saída não é objeto JSON válido summary_parse_failed Sem reparo adicional do resumo Continua com fallback; revisar prompt/resultado

OpenAIClient não configura max_retries do SDK. Tokens/latência de LLMCallResult correspondem à tentativa final bem-sucedida; não use esses valores isolados para estimar todas as tentativas. Detalhes em OpenAI.

Webhook e entrega WhatsApp

Erro/status Causa/sintoma Log Retry? Ação e handoff
GET 403 verification_failed Token/mode de verificação incorreto webhook_received Repetir só após corrigir configuração Meta/env Conferir WHATSAPP_VERIFY_TOKEN e challenge; não há sessão
POST 400 bad_request Body ausente/JSON inválido/campos ausentes bad_input Reenviar payload corrigido Conferir contrato e bytes/base64; sem handoff de cliente válido
POST 401 invalid_signature HMAC ausente/incorreto whatsapp_signature_invalid Não repetir mesmo corpo sem corrigir assinatura Conferir app secret e bytes originais; não desabilitar proteção em produção
POST 403 forbidden Formato interno phone_number em Cloud mode internal_payload_rejected_in_cloud_mode Não Usar webhook Meta assinado; formato interno é de emulação
POST 200 ignored Status-only callback webhook_received Não necessário Sucesso sem mensagem processável, não defeito
whatsapp_http_400/401/403 Request/credencial/permissão/janela rejeitada whatsapp_cloud_send_http_failed Sem retry HTTP local; orchestrator pode reentregar via SQS Corrigir causa antes de reprocessar; não altera automaticamente para handoff
whatsapp_http_429/5xx Limite/indisponibilidade whatsapp_cloud_send_http_failed ao esgotar Até 2 retries locais, depois SQS no orchestrator Conferir fila e provider
OSError/URLError/JSON inválido Transporte ou response inesperada whatsapp_cloud_send_failed Client não repete; orchestrator repete item A resposta persistida pode ser reenviada; aceitação remota incerta exige cuidado com duplicidade
ValueError destino inválido Telefone sem dígitos Exceção antes do loop de HTTP Não resolve sem corrigir destino Revisar normalização/origem
Falha de envio síncrono Resposta direta do webhook não entregue sync_whatsapp_reply_failed Não tem o mesmo fluxo de reentrega do orchestrator Conferir recibo/caminho específico, credenciais e janela

success=True sem ID remoto é possível no client WhatsApp; callbacks de status não são confirmação durável de entrega neste código. Veja integração WhatsApp.

DynamoDB, concorrência e SQS

Erro/sinal Causa/sintoma Log/observação Retry? Ação e escalonamento
DynamoConditionFailedError Estado/sessão/lock mudou ou não existe Tratamento varia conforme consumidor Relê em operações humanas; CAS interno em projeção Reconsultar estado/posse; não remover ConditionExpression
ConditionalCheckFailedException no CAS CRM etag concorrente Repository relê até 8 vezes Sim, limitado Se esgotar: crm_sync_concurrent_update; investigar contenção
Could not update operator availability under contention 20 tentativas CAS de disponibilidade falharam Exceção na ação de operador Não faz fallback inseguro Repetir comando após reduzir contenção; preservar mapa de outros operadores
bad_sqs_body Corpo sem telefone/JSON inválido Evento com messageId Handler não reencaminha: considera irrecuperável Corrigir produtor e investigar mensagem; não esperar DLQ desse ramo
process_immediate_turn_failed / process_message_failed Exceção não tratada no processamento Stack/erro e correlação batchItemFailures pede retry do item Verificar causa antes de redrive; pode ir a DLQ após política SQS
whatsapp_send_failed Processamento persistiu, entrega falhou Evento de saída + item em falha Reutiliza texto persistido para reentrega Não repetir inferência manualmente; conferir provider e sessão ativa
buffer_already_flushed Evento legado sem buffer válido INFO Não Evento esperado de TTL/concorrência, sem trabalho a fazer
SDK DynamoDB indisponível/permissão negada Endpoint/tabela/role errados Exceção SDK no chamador/handler Depende do SDK e caminho Confirmar ambiente/tabela, IAM e endpoint local; não zerar tabela

O comentário de DynamoConditionFailedError menciona HTTP 409, mas não existe mapeamento universal para 409. No painel humano, conflitos são traduzidos em erro seguro e redirect 303; no SQS não há status HTTP ao usuário. Consulte DynamoDB e SQS para condições, visibilidade e DLQ.

CRM e projeção comercial

Erro Causa/sintoma Log/registro Retry? Ação e handoff
hubspot_missing_contact_identifier Sem telefone/email Evento com mesmo nome Não resolve repetindo Corrigir dados; confirmação pode virar api_failure
hubspot_http_401/403 Token/permissão hubspot_http_failed Não no client BLOCKED no worker; corrigir credencial/permissão
hubspot_http_404 Rota ou ID inexistente hubspot_http_failed Não cria substituto Worker BLOCKED; validar base e ID; não interpretar busca como vazia
hubspot_http_409 Conflito de unicidade hubspot_http_failed Contato pesquisa outra vez; deal não é upsert Contato pode recuperar por PATCH; deal bloqueia
hubspot_http_429 Limite hubspot_http_failed após retries aplicáveis Worker PENDING, backoff durável Aguardar próxima execução e observar backlog
hubspot_http_5xx / timeout/rede em PATCH Falha transitória hubspot_http_failed/hubspot_request_failed PENDING Retry de 1 até 60 minutos
Erro de POST de deal sem prova de rejeição Pode ter criado remotamente UNCERTAIN, deal_sync_failed Não repete criação Confirmar no CRM antes de intervenção
hubspot_missing_deal_id após POST Resposta sem ID UNCERTAIN Não Investigar resultado remoto
hubspot_invalid_response JSON inválido Evento com mesmo nome No POST torna criação incerta Validar contrato; não reconstruir deal automaticamente
stage_configuration_invalid Stage ausente/terminal igual ao ativo CRM_SYNC.last_error, status BLOCKED Não automático Configurar stages explícitos e recuperar projeção controladamente
creation_result_unknown Marca de criação persistida sem ID após lease CRM_SYNC.last_error, UNCERTAIN Não Reconciliação externa obrigatória antes de liberar POST
crm_deal_id_persist_failed CRM respondeu, mas ID não pôde ser salvo crm_sync_worker_failed Lease/marca preservados Conferir negócio remoto e vínculo; evitar duplicar

Client comum tem retry HTTP, mas src/crm_sync/app.py fixa zero e delega retry à projeção durável. Falhas síncronas de contato na confirmação ainda podem gerar api_failure; falha posterior de projeção não desfaz atendimento fechado. O worker grava last_error genérico (contact_sync_failed, deal_sync_failed) e classifica o estado; procure logs do adapter para o HTTP específico. Veja CRM e sincronização.

eGestor e confirmação cadastral

Erro Causa/sintoma Log Retry? Ação e handoff
egestor_missing_document Ausente/tamanho diferente de 11/14 dígitos Mesmo nome Não Corrigir documento; sem HTTP
egestor_lookup_invalid_response Paginação/tipos/total/candidato inválidos egestor_customer_lookup_blocked Não escreve Conferir contrato; api_failure na confirmação
egestor_lookup_unsafe Candidatos sem documento exato egestor_customer_lookup_blocked Não escreve Investigar filtro; nunca aceitar primeiro resultado divergente
egestor_lookup_ambiguous Mais de um código para documento exato egestor_customer_lookup_blocked Não escreve Resolver duplicidade com equipe ERP
egestor_lookup_pagination_limit Mais de dez páginas egestor_customer_lookup_blocked Não escreve Conferir filtro e volume
egestor_http_401/403 Credencial/permissão egestor_http_failed Sem retry local Conferir token e troca OAuth; api_failure
egestor_http_404 inicial de lookup Contrato considera ausência Lookup resolvido para criação Pode prosseguir a POST Verificar base: 404 de rota incorreta também pode entrar nesse ramo
egestor_http_409 no POST Documento concorrente egestor_http_failed Refaz busca e atualiza somente exato Se não resolver, falha controlada
egestor_http_429/5xx ou rede Transitório egestor_http_failed/egestor_request_failed Até 2 retries default por request Esvaziamento leva a api_failure; sem rollback cross-provider
egestor_oauth_exchange_skipped Troca OAuth falhou DEBUG Usa token original; sem loop próprio OAuth Conferir tipo de token, endpoint e resposta
egestor_lookup_metric_failed CloudWatch negado/indisponível Mesmo nome Não libera lookup Corrigir observabilidade; mantém bloqueio de escrita
Campo inválido na confirmação Nome/email/CPF/CNPJ/CEP/UF/telefone/endereço/cidade/descrição Resposta fixa de correção Incrementa retry_count; não chama integrações Terceira falha gera confirm_retries_exhausted, handoff incerteza

Envelope vazio {"current_page":1,"last_page":0,"total":0,"data":[]} é aceito atualmente. Afirmar que toda resposta last_page=0 é erro repetiria uma regra já corrigida. Veja eGestor.

Handoff, autenticação e operação humana

Erro/sinal Causa/sintoma Log/HTTP Retry? Ação
queued ou stub não notificado Sem operador disponível ou simulação handoff_queued / stub_handoff_notify Não é falha técnica Verificar tipo, whitelist e opt-in do dia
Todos os operadores falharam HandoffNotifyResult.detail=send_failed handoff_operator_notified com sent=false, handoff_notify_failed Política WhatsApp por destino Sessão continua pendente; conferir canal
handoff_email_failed:<classe> SES falhou handoff_email_failed Retry em transitórios Conferir role, identidade SES, região e destinatários
Notificador lançou exceção Dependência inesperada handoff_notify_exception Orquestração mantém fila Investigar provider sem desfazer sessão
Renotificação fora de janela Último inbound não é recente handoff_renotify_outside_window Pode reconsiderar em próximo ciclo Não forçar mensagem ao cliente; equipe já pode ter sido notificada
HumanConversationError Texto vazio ou acima de 4096 caracteres Redirect 303 com erro seguro no painel Após corrigir entrada Não requer handoff adicional
ConversationNotFoundError Sessão ausente Erro seguro na tela Reconsultar Conferir telefone/sessão ativa
ConversationStateError Sessão saiu do estado esperado Redirect 303 Atualizar página Conferir ação concorrente/encerramento
ConversationOwnershipError Classe declarada, sem uso atual Não há fluxo ativo de exclusividade por owner Não aplicável Inbox é colaborativa entre operadores autenticados
CustomerWindowClosedError Sem inbound nos últimos 24 h Erro seguro na tela Só com nova mensagem do cliente Não há templates nesse fluxo
HumanMessageSendError por lock Envio simultâneo com lock de 90 s Mensagem “outra mensagem está sendo enviada” Aguardar Não enviar em paralelo
HumanMessageSendError por provider WhatsApp retornou falha Erro seguro na tela Tentativa deliberada após diagnóstico Atendimento permanece em andamento
Histórico falhou após envio Mensagem já foi enviada human_message_transcript_persist_failed; transcript_persisted=false Não reenviar Confirmar registro com suporte; mensagem da tela orienta não duplicar
Liberação de lock falhou Lock não removido após ação human_send_lock_release_failed Expira por lease Não converter sucesso de envio em retry do navegador
Sessão de operador expirada Cookie/token inválido ou fora do dia 401 operator session expired Novo login Usar entrar do telefone autorizado
CSRF inválido Token de formulário incorreto 403 invalid csrf token Recarregar/login Não desabilitar validação
Admin sem chave configurada ADMIN_API_KEY ausente 503 ADMIN_API_KEY is not configured Após configurar Não aceitar chave em URL
Admin com chave errada Header ausente/incorreto 401 invalid admin api key Após corrigir autenticação Usar X-Admin-API-Key, sem expor valor

Diagnóstico e testes

Rastreie uma ocorrência por request_id do handler, provider_message_id do receipt e session_id. No CRM, associe o item CRM_SYNC#<session_id> e o ID externo. Preserve uma cópia sanitizada do erro, camada, método, status, horários e decisão de retry; não cole tokens, documentos ou conversa real em tickets públicos. O formatter JSON mascara padrões/chaves conhecidas, mas exc_info não passa pelo mesmo scrub, e chaves externas novas podem escapar.

Testes de referência: tests/unit/application/test_parser.py, test_process_message_use_case.py, test_confirm_action.py, test_human_conversation.py, test_crm_sync.py, tests/unit/domain/test_states.py, test_codes.py, tests/unit/integrations/test_openai_client.py, test_hubspot_http_client.py, test_egestor_http_client.py, test_handoff_email_notifier.py, e tests/unit/shared/test_logging_scrubbing.py.

Não considere a existência de um teste prova de saúde externa atual. Para procedimentos de incidente use troubleshooting, observabilidade e smokes, mantendo a distinção entre leitura e operações reais.