Error Model (canonical error envelope)
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.kmdTelemetria (Groups A–G) Assíncrono, depois, app→reporter.koder.dev reporting.kmdBloco 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 (conditional → false + 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
- Mínimo sempre presente — nenhum campo de R1 é omissível; ausência é
violação de contrato (audit R7.1).
- PII nunca no envelope — o envelope cruza a rede e pode ser logado.
Aplicam-se as mesmas proibições de
reporting.kmd §7e a higiene deerror-handling.kmd §R8: sem nomeemailCPFtokenpath-com-username emmessage,context,causeoufields. Redigir antes de serializar. causeé finito — profundidade máxima 5; além disso, truncar emarcar
"cause_truncated": true. Evita envelopes recursivos gigantes.contexté small + estável — chaves de um conjunto conhecido porproduto; sem dumps de payload, sem valores de variáveis locais (
error-handling.kmd §R8proíbe variable capture sem amendment).recoveryobrigatório quandoretryable == falseporconditional—um erro condicionalmente recuperável deve dizer como recuperar; senão o cliente não distingue de
not-retryable.fieldsobrigatório paraerror_category == "VL"— validação sem odetalhe 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 mapeiaerror_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.kmdGroup 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_statusvira o status-code equivalente do transporte (verspecs/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 oerro internal → envelope na borda do handler. Um único helper
koderhttp.WriteError(w, err)serializa em problem+json. - Clientes:
koder_kitexpõeparseError(response) → KoderErrorcom oscampos de R1 garantidos e os de R2 opcionais.
R7 — Audit determinístico
error-model-audit.sh (advisory), via /k-housekeep:
- Resposta de erro de serviço Koder sem um dos 7 campos de R1 → error.
Content-Typede erro HTTP ≠application/problem+json→ warning.messagecontextcausecasando regex de PII (emailCPFtoken) → error.error_category == "VL"semfields→ warning.retryable == falsecom hint de condicionalidade nomessagemas semrecovery→ warning.- Texto localizado (pt-BR/en-US) detectado em
message→ warning (textohumano pertence ao cliente, R4).
Cross-link
specs/errors/taxonomy.kmd— defineerror_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 arrayfieldsem errosVL.specs/ipc/protocol.kmd— envelope sobre IPC não-HTTP.