#nextjs #error-handling #error-boundary #404

Day 13 — Error Handling: Breaking Gracefully

🧭 Day 13 — Error Handling: Breaking Gracefully

Zero to Hero — Hands-on Next.js Tutorial

In a perfect world, code never crashes. In the real world, APIs fail, databases timeout, and bugs happen. Next.js uses Error Boundaries to ensure that a crash in one part of your UI doesn’t break the whole app.


🟦 1. error.tsx

To handle runtime errors in a specific route segment, create an error.tsx file. Next.js naturally wraps your page.tsx in a React Error Boundary.

Rules for error.tsx:

  1. Must be a Client Component ('use client').
  2. Receives error and reset as props.
// src/app/dashboard/error.tsx
'use client'; // Error components must be Client Components

import { useEffect } from 'react';

export default function Error({
  error,
  reset,
}: {
  error: Error & { digest?: string }
  reset: () => void
}) {
  useEffect(() => {
    // Log the error to an error reporting service
    console.error(error);
  }, [error]);

  return (
    <div className="p-4 bg-red-50 border border-red-200 rounded">
      <h2 className="text-red-800 font-bold">Something went wrong!</h2>
      <button
        onClick={() => reset()} // Attempt to recover by re-rendering the segment
        className="bg-red-600 text-white px-4 py-2 mt-4 rounded hover:bg-red-700"
      >
        Try again
      </button>
    </div>
  );
}

Now, if /dashboard/page.tsx throws an error, the user sees this UI instead of a white screen crash. Critically, the Navigation (Sidebar/Header) stays visible and functional!


🟩 2. not-found.tsx

If you visit a route that doesn’t exist, Next.js serves a default 404. You can customize this by creating not-found.tsx.

It also works programmatically!

// src/app/not-found.tsx
import Link from 'next/link';
 
export default function NotFound() {
  return (
    <div>
      <h2>Not Found</h2>
      <p>Could not find requested resource</p>
      <Link href="/">Return Home</Link>
    </div>
  );
}

Triggering it manually:

import { notFound } from 'next/navigation';

async function fetchUser(id: string) {
  const user = await db.user.findUnique({ where: { id } });
  if (!user) {
    notFound(); // Renders the nearest not-found.tsx
  }
}

🟧 3. global-error.tsx

Your standard error.tsx cannot catch errors in the Root Layout (app/layout.tsx). To handle crashes at the very top level, use global-error.tsx.

This file replaces your Root Layout, so it must define its own <html> and <body> tags.


🧪 Challenge: Day 13

  1. Create a page /broken.
  2. Inside the component, throw an error: throw new Error("Oops!");.
  3. Visit the page. See the default Next.js error overlay (in dev) or 500 page (prod).
  4. Create app/broken/error.tsx.
  5. Visit the page again. See your custom error UI?
  6. Click the “Reset” button (it won’t fix it because we hardcoded the throw, but it handles the interaction!).

See you tomorrow for Route Handlers (API Routes)! 🛠️