Pular para o conteúdo

Error Model (canonical error envelope)

errors specs/errors/model.kmd

O envelope canônico, máquina-legível, de um erro na Koder Stack: os campos obrigatórios (dados mínimos exigíveis) e opcionais (dados complementares) de um objeto de erro, as regras para preencher os complementares, e o mapeamento para resposta HTTP (problem+json) que todo backend Koder emite e todo cliente parseia. É o contrato SÍNCRONO de erro entre serviços e clientes — distinto da telemetria assíncrona de `specs/errors/reporting.kmd` (que vai pro reporter) e do texto humano de `user-facing-messages.kmd`. Classes/severidade/retryability vêm de `specs/errors/taxonomy.kmd`.

Quando este padrão se aplica

Triggers primários

Todos os triggers

Corpo da especificação

Spec — Error Model (canonical envelope)

O shape de um erro que cruza um boundary (API HTTP/RPC, IPC, SDK). Vocabulário (classe/severidade/retryable) é specs/errors/taxonomy.kmd. Texto humano é user-facing-messages.kmd. Telemetria pro reporter é reporting.kmd. Esta spec é a fonte única do envelope síncrono.

Applicability

Toda resposta de erro que um componente Koder devolve a um chamador no momento da falha — respostas HTTP/RPC de serviços backend, erros de IPC (specs/ipc/protocol.kmd), erros propagados por bindings SDK. Não se aplica a erro internal entre funções de um mesmo processo (isso é idiom de linguagem — code/error-handling.kmd), nem ao payload de telemetria enviado ao reporter (reporting.kmd).

Distinção crítica. Há três payloads de erro distintos, com donos distintos — não confundir:

PayloadQuandoDono
Envelope (esta spec)Síncrono, no momento da falha, serviço→clientemodel.kmd
Telemetria (Groups A–G)Assíncrono, depois, app→reporter.koder.devreporting.kmd
Bloco de suporte (texto copiável)Manual, usuário→suporteuser-facing-messages.kmd §5

R1 — Campos obrigatórios (dados mínimos exigíveis)

Todo envelope de erro deve conter, no mínimo:

CampoTipoOrigem / regra
error_idstringFormato <PRODUCT>-<CATEGORY>-<CODE>-<SEQ> (user-facing-messages.kmd §4)
error_categorystring(2)Enum fechado de taxonomy.kmd §R1
codestringCODE do Error ID (HTTP status ou numérico do produto)
severitystringEnum de taxonomy.kmd §R3
retryableboolClassificação de taxonomy.kmd §R4 (conditionalfalse + recovery)
messagestringMensagem técnica verbatim (não humanizada; ver R4)
occurred_atstringISO 8601 com timezone (2026-04-17T15:42:30-03:00)

Esses sete são o contrato mínimo: um cliente pode decidir retry, exibir, logar e correlacionar com apenas eles.


R2 — Campos opcionais (dados complementares)

Incluídos quando disponíveis e quando R3 (regras de registro) permite:

CampoTipoConteúdo
request_idstringTrace ID da requisição (correlação com log/trace — observability-first.kmd)
causeobjectErro encadeado da camada inferior, mesmo schema (recursivo); espelha o wrapping de error-handling.kmd §R1
http_statusintStatus HTTP, quando aplicável
upstream_dependencystringServiço cuja falha originou este erro
recoverystringAção que torna um conditional retryable ("re-authenticate", "free_space", "fix_field:cpf")
contextobjectPares chave-valor do que se tentava ({"operation":"download","resource":"koder-hub@1.8.2"})
fieldsarrayPara VL: lista de {field, rule, message} (ver specs/data/validation.kmd)
doc_urlstringURL de documentação do erro (quando o produto a publica)

R3 — Regras para registro de dados complementares

  1. Mínimo sempre presente — nenhum campo de R1 é omissível; ausência é violação de contrato (audit R7.1).
  2. PII nunca no envelope — o envelope cruza a rede e pode ser logado. Aplicam-se as mesmas proibições de reporting.kmd §7 e a higiene de error-handling.kmd §R8: sem nome/email/CPF/token/path-com-username em message, context, cause ou fields. Redigir antes de serializar.
  3. cause é finito — profundidade máxima 5; além disso, truncar e marcar "cause_truncated": true. Evita envelopes recursivos gigantes.
  4. context é small + estável — chaves de um conjunto conhecido por produto; sem dumps de payload, sem valores de variáveis locais (error-handling.kmd §R8 proíbe variable capture sem amendment).
  5. recovery obrigatório quando retryable == false por conditional — um erro condicionalmente recuperável deve dizer como recuperar; senão o cliente não distingue de not-retryable.
  6. fields obrigatório para error_category == "VL" — validação sem o detalhe por-campo é inútil pro cliente corrigir (cross-link specs/data/validation.kmd §R-erros).

R4 — Relação com texto humano

  • O envelope carrega mensagem técnica, nunca a humanizada. A humanização é responsabilidade do cliente, via user-facing-messages.kmd (o humanizer mapeia error_category + code → template humano).
  • Um serviço não envia texto pt-BR/en-US "pronto pra UI" no message — isso acoplaria backend a locale do cliente. O backend manda error_category/code/message técnico; o cliente decide o texto.
  • O error_id é a cola: aparece no envelope (R1), no log do servidor (user-facing-messages.kmd §6), na telemetria (reporting.kmd Group D) e no bloco de suporte (user-facing-messages.kmd §5).

R5 — Mapeamento HTTP (problem+json)

Respostas de erro HTTP usam application/problem+json (RFC 9457) com extensões Koder. O status HTTP é o http_status; os campos Koder são membros de extensão.

HTTP/1.1 503 Service Unavailable
Content-Type: application/problem+json

{
  "type": "https://errors.koder.dev/DL/503",
  "title": "Service Unavailable",
  "status": 503,
  "detail": "download token service temporarily unavailable",
  "error_id": "HUB-DL-503-001",
  "error_category": "DL",
  "code": "503",
  "severity": "error",
  "retryable": true,
  "occurred_at": "2026-04-17T15:42:30-03:00",
  "request_id": "req-9f2a…",
  "upstream_dependency": "token-service"
}

Mapeamento RFC 9457 ↔ Koder:

RFC 9457KoderNota
statushttp_statusIdêntico; status é o membro padrão
titleCurto, estável por code (não localizar)
detailmessageMensagem técnica desta ocorrência
typederivadohttps://errors.koder.dev/<CATEGORY>/<CODE>
instancerequest_idQuando disponível

error_id, error_category, code, severity, retryable, occurred_at, cause, recovery, context, fields são membros de extensão Koder.

Para gRPC/RPC não-HTTP: mesmos campos como metadata/trailer; http_status vira o status-code equivalente do transporte (ver specs/ipc/protocol.kmd).


R6 — Implementação (SDK-first)

  • O envelope é construído e parseado pelo engines/sdk/koder_kit (KoderError / KoderErrorEnvelope), nunca remontado à mão por produto (policies/sdk-first.kmd).
  • Backends Go: middleware de boundary (error-handling.kmd §R3) converte o erro internal → envelope na borda do handler. Um único helper koderhttp.WriteError(w, err) serializa em problem+json.
  • Clientes: koder_kit expõe parseError(response) → KoderError com os campos de R1 garantidos e os de R2 opcionais.

R7 — Audit determinístico

error-model-audit.sh (advisory), via /k-housekeep:

  1. Resposta de erro de serviço Koder sem um dos 7 campos de R1 → error.
  2. Content-Type de erro HTTP ≠ application/problem+json → warning.
  3. message/context/cause casando regex de PII (email/CPF/token) → error.
  4. error_category == "VL" sem fields → warning.
  5. retryable == false com hint de condicionalidade no message mas sem recovery → warning.
  6. Texto localizado (pt-BR/en-US) detectado em message → warning (texto humano pertence ao cliente, R4).

  • specs/errors/taxonomy.kmd — define error_category, severity, retryable.
  • specs/errors/user-facing-messages.kmd — Error ID (§4) + humanização (cliente).
  • specs/errors/reporting.kmd — telemetria assíncrona (payload distinto).
  • specs/code/error-handling.kmd§R1 (cause chain), §R3 (boundary), §R8 (PII).
  • specs/data/validation.kmd — origem do array fields em erros VL.
  • specs/ipc/protocol.kmd — envelope sobre IPC não-HTTP.

Referências