Error Model (canonical error envelope)

mandatory

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`.

O shape de um erro que cruza um boundary (API HTTP/RPC, IPC, SDK). Vocabulário (classeseveridaderetryable) é 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:

Payload Quando Dono
Envelope (esta spec) Síncrono, no momento da falha, serviço→cliente model.kmd
Telemetria (Groups A–G) Assíncrono, depois, app→reporter.koder.dev reporting.kmd
Bloco de suporte (texto copiável) Manual, usuário→suporte user-facing-messages.kmd §5

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

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

Campo Tipo Origem / regra
error_id string Formato <PRODUCT>-<CATEGORY>-<CODE>-<SEQ> (user-facing-messages.kmd §4)
error_category string(2) Enum fechado de taxonomy.kmd §R1
code string CODE do Error ID (HTTP status ou numérico do produto)
severity string Enum de taxonomy.kmd §R3
retryable bool Classificação de taxonomy.kmd §R4 (conditionalfalse + recovery)
message string Mensagem técnica verbatim (não humanizada; ver R4)
occurred_at string ISO 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:

Campo Tipo Conteúdo
request_id string Trace ID da requisição (correlação com log/trace — observability-first.kmd)
cause object Erro encadeado da camada inferior, mesmo schema (recursivo); espelha o wrapping de error-handling.kmd §R1
http_status int Status HTTP, quando aplicável
upstream_dependency string Serviço cuja falha originou este erro
recovery string Ação que torna um conditional retryable ("re-authenticate", "free_space", "fix_field:cpf")
context object Pares chave-valor do que se tentava ({"operation":"download","resource":"koder-hub@1.8.2"})
fields array Para VL: lista de {field, rule, message} (ver specs/data/validation.kmd)
doc_url string URL 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 nomeemailCPFtokenpath-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_categorycodemessage 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 9457 Koder Nota
status http_status Idêntico; status é o membro padrão
title Curto, estável por code (não localizar)
detail message Mensagem técnica desta ocorrência
type derivado https://errors.koder.dev/<CATEGORY>/<CODE>
instance request_id Quando disponível

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

Para gRPCRPC não-HTTP: mesmos campos como metadatatrailer; 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. messagecontextcause casando regex de PII (emailCPFtoken) → 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.