Skip to content

feat(web): two error screens, because a blank page is the worst possible answer (E13-T09) - #104

Merged
danielgorgonha merged 2 commits into
mainfrom
feat/error-screens
Sep 21, 2026
Merged

danielgorgonha merged 2 commits into
mainfrom
feat/error-screens

Conversation

@danielgorgonha

Copy link
Copy Markdown
Member

Terceira fatia do E13 (#23).

O que existia

Só not-found.tsx. Qualquer exceção dentro de uma rota caía na tela branca do Next, que em produção
não tem texto nenhum.

Quem está do outro lado é alguém com medo de um documento jurídico. A tela branca não diz se o problema foi
dela, se o documento se perdeu, nem o que fazer. É a pior resposta possível.

As duas telas

error.tsx cobre a falha dentro de uma rota: diz que não foi ela e que nada do que ela fez se perdeu,
oferece tentar de novo, e dá duas saídas.

global-error.tsx cobre o layout raiz falhando. Ela substitui o layout inteiro, então desenha
<html> e <body> por conta — e não importa nada do produto, de propósito: se o que quebrou foi o
layout, a fonte ou o CSS global, importar o kit de componentes ali é pedir para a tela de erro quebrar junto
com o erro que ela veio explicar. As cores estão copiadas de tokens.css à mão pela mesma razão. Se os
tokens mudarem, ela fica um pouco fora do tom e continua legível, que é a única coisa que se pede dela.

O que elas não mostram

A mensagem crua da exceção. Ela é escrita para quem mantém o serviço e costuma carregar caminho de
arquivo, nome de coluna e pedaço de consulta.

O que elas mostram é o digest, que é o resumo que o Next gera justamente para ligar o que a pessoa
viu ao que ficou no log do servidor. É o que ela informa se precisar falar com alguém.

O teste, e o que ele não prova

Não há renderizador de DOM neste projeto, então lib/error-screen.test.ts lê o código-fonte. O teste diz
isso de si mesmo: não prova que a tela renderiza bem, e prova que ninguém pôs error.message nela.
Também trava a independência do global-error, que é o que faz dela a última rede.

86 testes no aplicativo, build limpo.

…ble answer

E13-T09. There was only not-found.tsx, so any exception inside a route fell through to Next's blank page,
which in production carries no text at all. The person on the other side is afraid of a legal document, and
a blank page does not tell her whether the problem was hers, whether her document is gone, or what to do.

error.tsx covers a failure inside a route: it says it was not her fault and that nothing she did was lost,
offers to try again, and gives two ways out.

global-error.tsx covers the root layout itself failing. It replaces the whole layout, so it draws <html> and
<body> on its own, and it deliberately imports nothing from the product: if what broke is the layout, the
font or the global stylesheet, importing the component kit here is asking the error screen to break along
with the error it came to explain. Its colours are copied from tokens.css by hand for the same reason. If
the tokens change, this screen drifts slightly out of tone and stays legible, which is all that is asked of
it.

Neither shows the raw exception message. That message is written for whoever maintains the service and
usually carries a file path, a column name or a fragment of a query. What both do show is the digest, which
is the summary Next generates precisely to tie what the person saw to what landed in the server log, and it
is what she reports if she needs to reach someone.

lib/error-screen.test.ts locks that. There is no DOM renderer in this project, so it reads the source, and
the test says so: it does not prove the screen renders well, and it does prove nobody put error.message on
it.
@vercel

vercel Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
leia Ready Ready Preview Sep 21, 2026 9:53am UTC

Request Review

Two mistakes of mine, both caught after the fact.

The prop is retry, not reset. Both exist in this version, and the docs bundled in node_modules say retry()
re-fetches and re-renders while reset() only clears the error state without re-fetching. For a transient
server failure, which is the case these screens serve, re-fetching is the whole point. I wrote reset from
memory, against the app's own AGENTS.md, which says in the first line that this is not the Next.js you know
and to read the bundled guide before writing any code.

Worse: the test I wrote asserted reset, and passed green. A source-level test locks in whatever the author
believes, right or wrong, so it now points at the documented prop and says why.

The second was an <a> where the repo's lint requires next/link. I had skipped pnpm lint locally on this
branch and only ran tsc, vitest and build, so CI found it instead of me. next/link does not weaken the rule
that global-error imports nothing from the product: it belongs to the framework drawing the screen, and if
it were broken the component would not have rendered at all. The comment now says that, because a reader
seeing the import right above "imports nothing" would be right to be confused.
@danielgorgonha
danielgorgonha merged commit ae73765 into main Sep 21, 2026
4 checks passed
@danielgorgonha
danielgorgonha deleted the feat/error-screens branch September 21, 2026 11:15

This branch was successfully deployed

1 active deployment
Preview — e87b69b4 Deployed Sep 21, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant