React
Error boundaries in the App Router: what error.tsx catches
`error.tsx` catches errors below its segment, not in the layout above. Boundary hierarchy, `global-error` and the catch that swallows redirects.
Key points
- `error.tsx` is a client component and receives `error` and `reset`.
- It does not catch errors from the layout that contains it: that needs the level above.
- `global-error.tsx` replaces the root layout and must declare `` and ``.
- A `try/catch` around `redirect()` or `notFound()` cancels the redirect.
In the App Router `error.tsx` is a client component that catches errors in the segment below it and renders a fallback with a reset button. It does not catch errors from the `layout` that contains it, nor from the root layout.
Where the file goes
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
The file is a React boundary: Next.js wraps the segment in an error boundary and passes two props, `error` and `reset`. It must carry `"use client"`, or the build rejects it.
// 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()` re-renders the segment without reloading the page. It helps when the error is transient, such as a failed fetch. If the cause is missing data, the retry produces the same error.
The boundary hierarchy
| Where the error starts | Who catches it |
|---|---|
| A `page.tsx` inside `app/dashboard` | `app/dashboard/error.tsx` |
| `app/dashboard/layout.tsx` | `app/error.tsx`, one level up |
| The root layout | `app/global-error.tsx` |
| An event handler in a client component | No boundary: use try/catch in the handler |
| `notFound()` | `not-found.tsx`, not `error.tsx` |
Why `global-error.tsx` exists
// app/global-error.tsx
"use client";
export default function GlobalError({ reset }: { reset: () => void }) {
return (
Errore imprevisto
reset()}>Ricarica
);
}
The global file replaces the root layout, so it must declare `` and `
`. It is the last net: without it, an error in the root layout falls through to the framework's own error page.The case that costs an afternoon
// 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()` and `notFound()` work by throwing a special error the router intercepts. A `try/catch` around that call turns it into a silent return: the page stays blank and no log explains why.
The number that matters
The EneUI catalogue indexes 111,985 components and 1,556 blocks from 1,472 libraries, measured on 1 November 2026 at `/api/stats`. The fallback needs error pages, alerts and error handling.
An error inside a slot follows the slot rules: see parallel routes and slots. For the arrival order of chunks there is streaming and Suspense. For the 404 that shows up after a deploy, 404 after deploy. For a framework comparison, Remix vs Next.js.
Known limitation: in production the server error message is replaced by generic text with a `digest`. The detail stays in the server logs, and without that digest you cannot link the fallback to its cause.
Frequently asked questions
Must `error.tsx` be a client component?
Yes. The boundary uses `useEffect` and `reset`, so it needs `"use client"`. Without the directive the build fails with an explicit error.
Why is my layout error not caught?
Because a boundary never covers its own parent. An error in `layout.tsx` rises to the `error.tsx` one level up, and the root layout needs `global-error.tsx`.
What is `digest` for?
It links the generic message shown in production to the server log. The error text never leaves the server; the digest does.
Does `reset` reload the page?
No. It re-renders the segment and retries rendering. For a full reload you call `location.reload()` or use a link.
Do event handler errors go through `error.tsx`?
No. A React boundary only catches render errors. A click that throws needs a `try/catch` inside the handler.