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 startsWho 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 componentNo 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.