error.tsx & global-error.tsx
error.tsx & global-error.tsx
Level 2 — App Router UI Elements Special files that automatically catch unexpected runtime errors in your Server or Client components, displaying a fallback UI instead of crashing the entire application.
1. Prerequisites
- React Error Boundaries — The underlying React feature that Next.js uses to catch errors in the UI.
loading.tsx— The sister file that handles pending promises instead of rejected ones.
2. Term Category
Routing & Layouts (Route Segment Error Boundary Component): error.tsx isolates runtime crashes within specific route segments by creating a React Error Boundary UI wrapper.
3. Explanation
Environment Context
- Client Component ONLY (Must use
"use client")
(1) Design Motivation — "Why did we design this?"
If a database query inside page.tsx fails and throws an error, standard React behavior is to unmount the entire component tree, resulting in a blank white screen (a fatal crash).
error.tsx prevents this. It acts as a safety net. If any component in the route throws an error, Next.js catches it and displays the UI inside error.tsx. Crucially, the rest of the application (like the layout.tsx navbar) stays completely functional!
(2) The Syntax
Important: An error.tsx file MUST be a Client Component ("use client"). This is because errors can happen on the server OR the client during hydration, so the Error Boundary must be able to execute in the browser to catch client-side clicks/events that throw errors.
It receives two props: the error object, and a reset function to try reloading the page.
// app/dashboard/error.tsx
"use client"; // REQUIRED!
export default function DashboardError({
error,
reset,
}: {
error: Error;
reset: () => void;
}) {
return (
<div className="bg-red-100 p-4 rounded">
<h2>Something went wrong in the dashboard!</h2>
<p>{error.message}</p>
{/* The reset function attempts to re-render the segment */}
<button onClick={() => reset()}>Try again</button>
</div>
);
}
(3) global-error.tsx
Just like loading.tsx, error.tsx only catches errors in page.tsx and nested components. It does not catch errors thrown inside the layout.tsx of the same folder!
If an error is thrown in the Root Layout (app/layout.tsx), the entire app dies. To catch errors in the Root Layout, you must use a special file called app/global-error.tsx. It replaces the root HTML document entirely when a catastrophic failure occurs.
4. Common Mistakes & Pitfalls
Mistake 1: Forgetting "use client"
The mistake: A developer writes an error.tsx file but forgets to put "use client" at the top.
Why it's wrong: Next.js will throw a massive build error. React Error Boundaries are a client-side React feature (they rely on lifecycle methods under the hood). Server Components cannot act as Error Boundaries.
Golden Rule: Always start error.tsx and global-error.tsx with "use client".
Mistake 2: Omitting 'use client' from error.tsx Files
The mistake: Creating error.tsx without the 'use client' directive.
Why it's wrong: Next.js error boundaries MUST be Client Components because they encapsulate React error state and provide recovery retry handlers (reset()).
Incorrect:
// app/error.tsx
export default function Error({ error, reset }) { ... } // ❌ Build error: error.tsx must be a Client Component!
Fix:
// app/error.tsx
'use client'; // Required for error boundary components
export default function Error({ error, reset }: { error: Error; reset: () => void }) { ... }
Mistake 3: Expecting error.tsx to Catch Errors Originating from its Same-Level layout.tsx
The mistake: Adding app/dashboard/error.tsx expecting it to catch runtime errors thrown inside app/dashboard/layout.tsx.
Why it's wrong: An error.tsx boundary catches errors ONLY for its child sub-segments. Errors inside a layout component MUST be caught by an error.tsx in a parent directory.
Incorrect:
/* Expecting error.tsx to catch errors inside same-folder layout.tsx */
Fix:
/* Move error.tsx to parent folder or use global-error.tsx for root layout errors */
5. Practice Exercises
Exercise 1: Isolating Route Failures with error.tsx
Scenario:
Create app/dashboard/error.tsx to handle failures inside the /dashboard route segment.
Requirements:
- Mark file with
"use client". - Export component accepting
{ error, reset }.
Answer
Implementation
// app/dashboard/error.tsx
"use client";
export default function DashboardError({
error,
reset
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<div className="p-6 bg-amber-50 text-amber-900 rounded-lg">
<h2 className="text-xl font-bold">Failed to load Dashboard data</h2>
<p className="mt-2 text-sm">{error.message}</p>
<button
onClick={() => reset()}
className="mt-4 px-4 py-2 bg-amber-700 text-white rounded"
>
Reload Dashboard Segment </button> </div>); }
#### Technical Explanation 1. `error.tsx` automatically wraps sibling `page.tsx` and child segments in a React Error Boundary. 2. `error.tsx` MUST be declared as a Client Component using `"use client"`. 3. Prevents dashboard errors from crashing the outer root layout.
Exercise 2: Recovering Route State with reset() and router.refresh()
Scenario:
Combine reset() with router.refresh() to fetch fresh server data when retrying a failed route.
Requirements:
- Execute
startTransition(() => { router.refresh(); reset(); }).
Answer
Implementation
"use client";
import { useRouter } from "next/navigation";
import { startTransition } from "react";
export default function RouteError({
error,
reset
}: {
error: Error;
reset: () => void;
}) {
const router = useRouter();
function handleRetry() {
startTransition(() => {
router.refresh();
reset();
});
}
return (
<div>
<p>Error: {error.message}</p>
<button onClick={handleRetry}>Refresh Data & Retry</button>
</div>
);
}
Technical Explanation
reset()re-renders the failed client component tree but does NOT re-execute Server Component data fetches alone.router.refresh()re-fetches Server Components from the server.- Wrapping both in
startTransitionperforms a complete, synchronized retry.
Exercise 3: Handling Global Root Layout Errors with global-error.tsx
Scenario:
Create app/global-error.tsx to handle errors originating inside app/layout.tsx.
Requirements:
- Define
<html>and<body>tags inglobal-error.tsx.
Answer
Implementation
// app/global-error.tsx
"use client";
export default function GlobalError({
error,
reset
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<html lang="en">
<body className="p-8 bg-slate-900 text-white">
<h1 className="text-2xl font-bold">Critical Application Error</h1>
<p className="mt-2">{error.message}</p>
<button onClick={() => reset()} className="mt-4 px-4 py-2 bg-blue-600 rounded">
Hard Reset
</button>
</body>
</html>
);
}
Technical Explanation
error.tsxdoes NOT catch errors thrown inside the same folder'slayout.tsx.global-error.tsxhandles errors occurring in the rootapp/layout.tsxfile.- Must include its own
<html>and<body>tags because the root layout was unmounted.
6. Related Terms
- React Error Boundaries — The native React feature that Next.js wraps to create this file.
not-found.tsx¬Found()— A specific type of error file for 404s.loading.tsx— Related concept:loading.tsx.page.tsx— Page component.
7. Key Takeaways
error.tsxcatches unexpected errors in your route and displays a fallback UI, preventing the whole app from crashing.- It MUST be a Client Component (
"use client"). - It receives an
errorobject and areset()function to allow the user to retry the action. - It does not catch errors in the
layout.tsxof the same folder (they bubble up to the parent folder's error boundary). global-error.tsxis used specifically to catch errors in the Root Layout.