fix: EditEntryDialog para de ler err.message, mascarado em produção (closes #122) - #137
fix: EditEntryDialog para de ler err.message, mascarado em produção (closes #122)#137Guiroos wants to merge 2 commits into
Conversation
O único err.message que sobrava no repo (o resto foi convertido na #34) sempre exibe o parágrafo genérico do React em produção, porque erro que atravessa a fronteira de Server Action chega ao cliente reconstruído como Error genérico. A string pt-BR já existia no arquivo e nunca era exibida. Closes #122
Guiroos
left a comment
There was a problem hiding this comment.
Revisão do head 6536541. A correção em si está certa e fecha a #122 por inteiro — reconferi a enumeração pelo conteúdo, não pelo caminho: grep -rnE '\b(err|error|e)\s*\.\s*message\b' sobre app/, components/ e lib/ devolve zero ocorrências depois do PR, então não sobrou site fora do recorte da issue (que só falava de .tsx). O par console.error + string pt-BR fixa é o padrão já estabelecido pela correção da #35 em ui/row-actions.tsx, e a decisão de não converter updateDebtEntry para ActionResult está declarada no corpo e alinhada ao julgamento registrado na #34 — nada de substituição silenciosa de proposta.
O gate novo cobre de verdade, e verifiquei em vez de assumir: revertendo EditEntryDialog.tsx para a linha anterior e rodando npx vitest run __tests__/unit/no-err-message.test.ts, ele fica vermelho; com a correção, verde (suíte cheia: 34 arquivos, 527 testes, mais lint e typecheck limpos nesta sessão). Também derruba as duas correções erradas que a issue nomeou, porque as duas continuam lendo .message.
Um achado, não-bloqueante, e é sobre o regex, não sobre o fix: a janela catch[\s\S]{0,200}? foi copiada literal da issue junto com a justificativa dela — "sem ela o gate nasce falso-positivo" —, e essa justificativa é falsa. Medi: o regex sem a janela dá zero hits nos 171 .tsx de app/ + components/, FeedbackDialog.tsx incluído. Em troca, a janela abre um ponto cego de 241 chars no formato console.error(...) + toast.error(...) — o padrão que este próprio PR institui. Correção de uma linha, com a alternativa já verificada contra os mesmos arquivos, no comentário inline.
Generated by Claude Code
…e catch
A janela catch[\s\S]{0,200}? ficava cega assim que um console.error(...)
— o próprio remédio que este arquivo institui — empurrava o toast.error(...)
para fora dela. O falso-positivo que a janela existia para evitar
(errors.message, next.message como chave de mapa de formulário) não
ocorre de fato: \b antes de err/error/e não casa no meio de "errors"/"next".
Ancorar no sink (toast.*) em vez de numa distância é mais fiel ao achado
da #122: o defeito não é ler err.message, é exibi-lo ao usuário.
Aponta review em #137
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019Wgc6FNhxJPveiPvq6PjQd
O que mudou
components/devedores/EditEntryDialog.tsxera o último site do repo lendoerr.messagepara decidir a mensagem de erro exibida ao usuário. Erro que atravessa a fronteira de Server Action chega ao cliente RSC reconstruído como umErrorgenérico em build de produção (resolveErrorProd), entãoerr instanceof Erroré sempre verdadeiro e.messageé sempre o mesmo parágrafo em inglês sobre "Server Components render" — a string pt-BR'Erro ao editar lançamento.'já existia no arquivo e nunca era exibida.} catch (err) { - toast.error(err instanceof Error ? err.message : 'Erro ao editar lançamento.') + console.error('[EditEntryDialog] updateDebtEntry falhou', err) + toast.error('Erro ao editar lançamento.') }Por que dessa forma
Segui a proposta da issue à risca:
console.error+toast.errorfixo, não só removererr.message: sem o log, ocatchvira o "handler que engole a exceção sem log nem feedback" que oCLAUDE.mdproíbe — é o mesmo remédio já aplicado emcomponents/ui/row-actions.tsx(correção da [types] RowActions afirma "item em uso" para qualquer falha de exclusão, mas 7 das 8 actions que ele aciona não têm esse modo de falha #35), então não é padrão novo, é o padrão do repo chegando ao último arquivo que faltava.updateDebtEntryparaActionResult— a [types] Mensagens de erro de Server Actions são mascaradas em produção — 5 componentes exibemerr.messageque nunca chega ao usuário #34 já examinou e descartou essa rota para esta action (as falhas que ela lança hoje são da classe excepcional quelib/actions/types.tsmanda manter comothrow), e a issue [types] O únicoerr.messageque sobrou no repo torna o fallback pt-BR inalcançável — editar lançamento de devedor exibe o parágrafo em inglês do React em toda falha #122 não revisita esse julgamento.err.digestcomo substituto: é hash de mensagem + stack, instável entre builds, e não diz nada ao usuário.Como testei
npm run lint && npm run format:check && npm run typecheck && npm test && npm run build— todos verdes (35 arquivos, 528 testes).__tests__/unit/no-err-message.test.ts— gate por string sobre o código-fonte (precedente:row-actions.test.ts), varreapp/**/*.tsxecomponents/**/*.tsxprocurandoerr.message/error.messagedentro de umcatch. Validado manualmente que o regex: (a) rejeita o código anterior ao fix, (b) passa com a correção, (c) não gera falso-positivo emFeedbackDialog.tsx, que usaerrors.messagecomo chave de mapa de validação de formulário, sem relação com exceção.npm run test:integrationnão foi rodado — exige credenciais do Neon e só roda em push paramain; esta mudança não toca camada de banco.Risco e o que NÃO foi coberto
@testing-library/react); a cobertura fica no nível de gate por texto-fonte, mesmo padrão de achados de a11y/tipos anteriores.catchdeEditEntryDialog.tsxfoi tocado.Arquivos tocados
components/devedores/EditEntryDialog.tsx__tests__/unit/no-err-message.test.ts(novo)Closes #122
Generated by Claude Code