React

Error boundary nell'App Router: cosa cattura error.tsx

error.tsx cattura gli errori del segmento sotto, non del layout che lo contiene. Gerarchia dei confini, global-error e il catch che inghiotte i redirect.

In sintesi

  • `error.tsx` è un client component e riceve `error` e `reset`.
  • Non cattura gli errori del layout che lo contiene: serve il livello sopra.
  • `global-error.tsx` sostituisce il root layout e deve dichiarare `` e ``.
  • Un `try/catch` attorno a `redirect()` o `notFound()` annulla il redirect.

In App Router `error.tsx` è un client component che cattura gli errori del segmento sotto di sé e mostra un fallback con un pulsante di reset. Non cattura gli errori del `layout` che lo contiene, né quelli del root layout.

Dove va il file

app/
  error.tsx          # cattura gli errori sotto, non quelli del root layout
  global-error.tsx   # ultimo confine: sostituisce html e body
  not-found.tsx
  dashboard/
    error.tsx
    loading.tsx
    page.tsx

Il file è un confine React: Next.js avvolge il segmento in un error boundary e passa due props, `error` e `reset`. Deve avere `"use client"`, altrimenti la build lo rifiuta.

// app/dashboard/error.tsx
"use client";

import { useEffect } from "react";

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

  return (
    
      Qualcosa è andato storto
       reset()}>Riprova
    
  );
}

`reset()` rirenderizza il segmento senza ricaricare la pagina. Serve quando l'errore è transitorio, per esempio una fetch fallita. Se la causa è un dato mancante, il retry produce lo stesso errore.

La gerarchia dei confini

Dove nasce l'erroreChi lo cattura
Una `page.tsx` dentro `app/dashboard``app/dashboard/error.tsx`
`app/dashboard/layout.tsx``app/error.tsx`, il livello sopra
Il root layout`app/global-error.tsx`
Un event handler in un client componentNessun boundary: serve un try/catch nell'handler
`notFound()``not-found.tsx`, non `error.tsx`

Perché serve `global-error.tsx`

// app/global-error.tsx
"use client";

export default function GlobalError({ reset }: { reset: () => void }) {
  return (
    
      
        Errore imprevisto
         reset()}>Ricarica
      
    
  );
}

Il file globale sostituisce il root layout, quindi deve dichiarare `` e ``. È l'ultima rete: se non c'è, un errore nel root layout produce la pagina di errore del framework.

Il caso che costa un pomeriggio

// app/bozza/[id]/page.tsx
import { redirect } from "next/navigation";

export default async function Page(props: { params: Promise }) {
  const { id } = await props.params;
  try {
    const draft = await getDraft(id);
    if (!draft) redirect("/404"); // lancia un errore di controllo: mai dentro un try
  } catch {
    return null; // il redirect non arriva mai al router
  }
}

`redirect()` e `notFound()` funzionano lanciando un errore speciale che il router intercetta. Un `try/catch` attorno a quella chiamata lo trasforma in un ritorno silenzioso: la pagina resta bianca e nessun log lo spiega.

Il numero che conta

Il catalogo EneUI indicizza 111.985 componenti e 1.556 blocchi da 1.472 librerie, misurati il 1 novembre 2026 su `/api/stats`. Per il fallback servono error page, alert e error handling.

Un errore dentro uno slot segue le regole dello slot: vedi route parallele e slot. Per l'ordine di arrivo dei pezzi c'è streaming e Suspense. Per il 404 che compare dopo il deploy 404 dopo il deploy. Per il confronto tra framework Remix vs Next.js.

Limite noto: in produzione il messaggio degli errori server viene sostituito da un testo generico con un `digest`. Il dettaglio resta nei log del server, e senza quel digest non puoi collegare il fallback alla causa.

Domande frequenti

`error.tsx` deve essere un client component?

Sì. Il boundary usa `useEffect` e `reset`, quindi richiede `"use client"`. Senza la direttiva la build fallisce con un errore esplicito.

Perché il mio errore nel layout non viene catturato?

Perché un boundary non copre il proprio genitore. L'errore nel `layout.tsx` sale al `error.tsx` del livello superiore, e il root layout richiede `global-error.tsx`.

A cosa serve `digest`?

A collegare il messaggio generico mostrato in produzione al log del server. Il testo dell'errore non esce dal server, il digest sì.

`reset` ricarica la pagina?

No. Rirenderizza il segmento e ritenta il rendering. Per un reload completo devi chiamare `location.reload()` o usare un link.

Gli errori negli event handler passano da `error.tsx`?

No. Un boundary React cattura solo errori di rendering. Un click che lancia un'eccezione richiede un `try/catch` nell'handler.