Capítulo 114 de 456

error.js

Core Idea

error.js cria um React Error Boundary automático para um segmento de rota e seus filhos, exibindo UI de fallback quando um erro é lançado durante a renderização.

Key Concepts

  • Error boundary obrigatoriamente Client Component: error.js precisa de 'use client'.
  • Escopo do wrap: error.js envolve loading.js, not-found.js, page.js e layout.js aninhados abaixo dele, mas NÃO envolve o layout.js/template.js do mesmo segmento (acima dele na árvore).
  • error: objeto Error passado como prop; em dev inclui a mensagem original; em produção, erros vindos de Server Components mostram mensagem genérica + digest (hash para casar com logs do servidor), erros de Client Components mantêm a mensagem original.
  • retry(): tenta recuperar re-fetchando e re-renderizando os filhos do boundary; se funcionar, substitui a UI de erro pelo resultado.
  • reset(): limpa o estado de erro e re-renderiza sem re-fetch (caso específico; prefira retry() na maioria dos casos).
  • global-error.jsx: trata erro no root layout; precisa definir suas próprias tags <html>/<body> e estilos, pois substitui o layout raiz inteiro e não herda tema/CSS global; não suporta metadata/generateMetadata (não é Server Component).

Code Examples

'use client' // Error boundaries must be Client Components

import { useEffect } from 'react'

export default function Error({
  error,
  retry,
}: {
  error: Error & { digest?: string }
  retry: () => void
}) {
  useEffect(() => {
    console.error(error)
  }, [error])

  return (
    <div>
      <h2>Something went wrong!</h2>
      <button onClick={() => retry()}>Try again</button>
    </div>
  )
}
  • O que demonstra: error.js básico, logando o erro em useEffect e oferecendo recuperação via retry().
'use client'

export default function GlobalError({
  error,
  retry,
}: {
  error: Error & { digest?: string }
  retry: () => void
}) {
  return (
    // global-error must include html and body tags
    <html>
      <body>
        <h2>Something went wrong!</h2>
        <button onClick={() => retry()}>Try again</button>
      </body>
    </html>
  )
}
  • O que demonstra: global-error.jsx substituindo o root layout inteiro, com <html>/<body> próprios.

Anti-patterns

  • error.js sem 'use client': obrigatório, error boundaries só existem como Client Component.
  • Esperar que error.js capture erro do próprio layout.js do mesmo segmento: não captura; erros do layout acima precisam de error.js no segmento pai, ou global-error.jsx para o root layout.
  • Aplicar tema/dark-mode global e esperar que apareça em global-error: ele renderiza documento próprio, sem os estilos globais da app; aplique o tema manualmente dentro do componente.
  • Usar metadata/generateMetadata em global-error.jsx: não suportado (não é Server Component); use <title> do React se precisar.

Key Takeaways

  1. Escolha retry() como padrão de recuperação; reset() só quando não quer re-fetch.
  2. error.digest é o elo entre o que o usuário vê em produção e os logs reais do servidor.
  3. Para degradação graciosa (preservar último HTML renderizado), implemente um error boundary customizado que capture o HTML antes do erro, como no padrão GracefullyDegradingErrorBoundary.
  4. retry virou estável na v16.3.0 (antes era unstable_retry desde v16.2.0).

Connects To

  • File-system conventions (ch111): índice das convenções.
  • not-found.js (ch122) e forbidden.js (ch115): outras páginas de fallback especial que error.js envolve.
  • loading.js (ch120): também envolvido pelo error.js no mesmo segmento.