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'errore | Chi 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 component | Nessun 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.