User-Facing Error Messages
errors specs/errors/user-facing-messages.kmd
Toda mensagem de erro exibida a usuário final deve ter (1) texto humanizado em pt-BR/en-US, (2) botão "Ver detalhes" expandindo o erro técnico bruto, (3) ID único `<PRODUCT>-<CAT>-<CODE>-<SEQ>` para correlação com logs e suporte. Aplica-se a apps mobile/desktop/web, landing pages e CLI.
When this pattern applies
Primary triggers
- Exibir qualquer mensagem de erro a um usuário final (UI mobile/desktop/web/CLI)
All triggers
- Exibir qualquer mensagem de erro a um usuário final (UI mobile/desktop/web/CLI)
- Desenhar fluxo de erro recuperável ou não-recuperável em app Koder
Specification body
Spec — User-Facing Error Messages
Applicability
All Koder products that display errors to end users — mobile apps, desktop apps, web apps, web landing pages, CLI tools, and any product surface where a non-developer user can encounter an error.
Out of scope: server-side logs, developer-only consoles, internal admin dashboards (audience is technical and benefits from raw errors).
1. Required Anatomy
Every error displayed to a user must have three parts:
- Humanized message — short, clear, non-technical. States what happened and what the user can do. Localized: pt-BR for Brazilian users, en-US otherwise (see
policies/language.kmd). - "View details" affordance — a button, link, or expandable section labeled "Ver detalhes" (pt-BR) / "View details" (en-US). On activation, reveals the raw technical error (exception type, stack trace, HTTP status, response body).
- Error ID — a unique, copyable identifier shown in both the humanized message and the details panel. Format:
<PRODUCT>-<CATEGORY>-<CODE>-<SEQ>(e.g.,KSTORE-DL-503-001).
Forbidden: showing only the technical error to the user (e.g., Exception: BAD_DECRYPT(e_chacha20poly1305.cc:323)). Forbidden even as a fallback.
2. Humanized Message Rules
- One sentence, max ~120 characters. If the user needs more, put it after the period.
- Active voice, present tense. "Não foi possível baixar" not "O download falhou de ser possível".
- Tell the user what to do when there's a clear next step ("Tente novamente em alguns segundos", "Verifique sua internet").
- Never blame the user unless they actually caused it (typed wrong password = OK to say so; server bug ≠ user fault).
- Never use jargon: avoid "token", "TLS", "handshake", "503", "exception", "stack trace", "endpoint", "API", "DNS", "MAC", "decrypt".
- No emojis in the text itself (icon next to the message is OK if the product uses icons consistently).
Standard templates
| Situation | pt-BR | en-US |
|---|---|---|
| Servidor temporariamente indisponível (5xx, timeout) | "Servidor ocupado. Tente novamente em alguns segundos." | "Server busy. Please try again in a few seconds." |
| Recurso não encontrado (404) | "Conteúdo indisponível no momento." | "Content unavailable right now." |
| Falha de rede / sem conexão | "Sem conexão. Verifique sua internet e tente novamente." | "No connection. Check your internet and try again." |
| Erro de TLS / handshake / decrypt | "Conexão instável. Tente novamente." | "Unstable connection. Please try again." |
| Espaço insuficiente | "Espaço insuficiente no dispositivo." | "Not enough space on device." |
| Permissão negada (auth) | "Você precisa entrar na sua conta para continuar." | "You need to sign in to continue." |
| Permissão negada (autorização) | "Você não tem permissão para essa ação." | "You don't have permission for this action." |
| Versão do app obsoleta | "Atualize o aplicativo para continuar." | "Please update the app to continue." |
| Dados inválidos enviados pelo usuário | "Verifique os dados informados." | "Please check the information entered." |
| Operação cancelada pelo usuário | (não mostrar erro) | (do not show error) |
| Erro desconhecido (fallback) | "Algo deu errado. Toque em "Ver detalhes" se precisar reportar." | "Something went wrong. Tap "View details" to report it." |
Products may add product-specific templates, but the categories above are the baseline.
3. "View details" Panel
When the user activates the affordance, show:
- Error ID (large, copyable, prominent at the top)
- Timestamp in ISO 8601 with timezone (
2026-04-17T15:42:30-03:00) - Technical message — the original exception, stack trace, HTTP status + body, system call error, etc. Verbatim, no rewriting.
- Context — what the user was trying to do (e.g., "Downloading koder-hub v1.8.2 for android/arm64")
- App version and OS/platform (e.g., "Koder Hub 2.29.59 · Android 15 · arm64")
- Copy button that copies the entire details block as plain text, formatted so the user can paste into chat/email to support.
The details panel must be collapsed by default. Users should not see it unless they ask for it.
4. Error ID Format
<PRODUCT>-<CATEGORY>-<CODE>-<SEQ>
- PRODUCT — uppercase product slug, max 8 chars (
KSTORE,DEK,KMAIL,TALK,KORTEX) - CATEGORY — 2-letter functional area:
DLdownload ·UPupload ·AUauth ·NWnetwork ·DBdatabase/storageUIUI render ·IOfilesystem ·PMpermission ·VLvalidation ·XXunknown
- CODE — HTTP status (
503,404) for HTTP errors; otherwise a short numeric code defined by the product - SEQ — 3-digit zero-padded sequence to disambiguate multiple call sites with the same category+code (
001,002, ...)
Examples:
KSTORE-DL-503-001— Store download token service unavailableKSTORE-DL-404-001— Store download file missing on storageKSTORE-NW-000-001— Store network connection failed (no HTTP response)DEK-AU-401-001— Dek user authentication requiredKMAIL-UP-507-001— Kmail attachment upload exceeded storage quota
Each product maintains its error-ID registry in <product>/docs/technical/errors.md. The registry lists every ID, its trigger condition, the humanized message used, and the call site (file:line).
5. Reporting Channel
The "Copy" button in the details panel formats the report as:
Erro: KSTORE-DL-503-001
Quando: 2026-04-17T15:42:30-03:00
App: Koder Hub 2.29.59
Sistema: Android 15 (arm64)
Fazendo: Baixando atualização do Koder Hub v1.8.2
Detalhes técnicos:
Exception: Failed to get download token (503): {"error":"Service Unavailable","message":"token service temporarily unavailable"}
Products that have an in-app feedback channel (Settings → Help → Report a problem) must pre-fill that channel with this block. Products without an in-app channel must show a "Copy" button that puts the block on the clipboard so the user can paste into Slack/email/WhatsApp/support form.
6. Implementation Notes
Flutter (mobile + desktop)
- Centralize humanization in
lib/core/error_humanizer.dart(or equivalent). Single function:HumanizedError humanize(Object exception, ErrorContext ctx). - All
try/catchblocks that surface errors to UI must route through the humanizer. DirectSnackBar(content: Text(e.toString()))is forbidden. - The error display widget (
ErrorBanner,ErrorDialog, etc.) is a single shared widget that takes aHumanizedErrorand renders the three parts (message, details affordance, ID).
Web apps
- Centralize in
src/errors/humanize.ts(or equivalent). Same single-function API. - The error UI component is a shared React/Vue component used everywhere errors surface.
- The details panel uses a native
<details>element or a styled disclosure widget — must be keyboard-accessible.
Backend
- Backend services must include the error ID in their JSON error responses when possible:
{"error_id": "KSTORE-DL-503-001", "error": "Service Unavailable", "message": "token service temporarily unavailable"} - The same error ID must appear in the server log line for that request, so support can correlate the user's report with the log.
CLI tools
- CLIs print the humanized message to stderr.
- A
--verboseor-vflag (or simply the presence of$DEBUG) enables the technical details + error ID inline. - Without verbose, append a hint:
Use --verbose para ver detalhes técnicos.
7. Audit Checklist (run by /k-housekeep)
For each product surface:
- Grep for raw exception display — flag any
Text(e.toString()),print(e),console.error(e)that reaches user UI. - Confirm shared humanizer exists —
error_humanizer.dart(Flutter) /humanize.ts(web) present and exported. - Confirm shared error widget exists — single
ErrorBanner/ErrorDialogcomponent, no inline error UI scattered. - Confirm error registry exists —
<product>/docs/technical/errors.mdwith at least one entry per known error ID. - Confirm backend includes
error_idin JSON error responses (when product has a backend). - Confirm copy/report affordance present in the details panel.
Failures are listed in the housekeep report; products with violations cannot pass a release audit.
8. Migration Guidance
Existing products are exempt until their next release. On the next release:
- Add the shared humanizer + error widget if missing.
- Add error IDs starting at
001per category as call sites are touched. Backfilling all call sites at once is not required — incremental adoption is fine, as long as new code follows the spec. - Each release note must mention which error categories now have humanized messages, so users notice the improvement.
References
specs/errors/reporting.kmdengines/sdk/koder_kit