Useful Cheatsheetsusefulcheatsheets.com
Next.js Error Handling
Chapter 18 · Page 126
Intermediate

Next.js Error Handling

Implement custom error pages, error boundaries, and global error handling strategies.

TL;DR

  1. 01Create error.tsx files for segment-level error boundaries.
  2. 02Create not-found.tsx for 404 pages.
  3. 03Handle errors in server actions and API routes explicitly.

Tips

  1. 01Place global-error.tsx in the app root but rely on segment-level error.tsx files for most recovery UI — they give users more context-specific error messages.

Warnings

  1. 01Never expose sensitive error details to users — log detailed errors server-side and show friendly messages to clients.
Notes
Useful Cheatsheetsusefulcheatsheets.com
Next.js Error Handling
Chapter 18 · Page 127
Intermediate

Next.js Error Handling

(continued)

Error Boundaries with error.tsx

  • Create error.tsx for segment-level error handling.
    // app/blog/error.tsx
    "use client";
    
    import { useEffect } from "react";
    
    export default function Error({
      error,
      reset,
    }: {
      error: Error & { digest?: string };
      reset: () => void;
    }) {
      useEffect(() => {
        console.error(error);
      }, [error]);
      
      return (
        <div>
          <h2>Something went wrong!</h2>
          <button onClick={() => reset()}>Try again</button>
        </div>
      );
    }
  • Error boundaries catch errors from child segments.
  • Reset function allows users to retry.
  • Must be a client component with "use client" directive.
  • Nest error.tsx at each route level for targeted recovery — an error in /dashboard won't break the nav.
    app/
      error.tsx           # catches app-level errors
      dashboard/
        error.tsx         # catches only dashboard errors
        settings/
          error.tsx       # catches only settings errors
Notes
Useful Cheatsheetsusefulcheatsheets.com
Next.js Error Handling
Chapter 18 · Page 128
Intermediate

Next.js Error Handling

(continued)

Custom 404 Pages

  • Create not-found.tsx for missing resources.
    // app/blog/[slug]/not-found.tsx
    export default function NotFound() {
      return (
        <div>
          <h1>Post not found</h1>
          <p>The post you're looking for doesn't exist.</p>
        </div>
      );
    }
  • Use notFound() function to trigger the not-found page.
    import { notFound } from "next/navigation";
    
    export default async function Post({ params }: { params: Promise<{ slug: string }> }) {
      const { slug } = await params;
      const post = await getPost(slug);
      if (!post) {
        notFound();
      }
      return <article>{post.content}</article>;
    }
  • Each segment can have its own not-found.tsx.
  • Add a root-level not-found.tsx for app-wide 404 handling.
    // app/not-found.tsx
    import Link from "next/link";
    
    export default function RootNotFound() {
      return (
        <div>
          <h1>Page not found</h1>
          <Link href="/">Go home</Link>
        </div>
      );
    }
  • Export metadata from not-found.tsx for SEO.
    export const metadata = {
      title: "404 — Page not found",
      description: "This page does not exist."
    };
Notes
Useful Cheatsheetsusefulcheatsheets.com
Next.js Error Handling
Chapter 18 · Page 129
Intermediate

Next.js Error Handling

(continued)

Server Action Error Handling

  • Catch and handle errors in server actions.
    "use server";
    
    export async function createPost(formData: FormData) {
      try {
        const title = formData.get("title") as string;
        if (!title) {
          return { error: "Title is required" };
        }
        
        const post = await db.post.create({ data: { title } });
        return { success: true, post };
      } catch (error) {
        return { error: "Failed to create post" };
      }
    }
  • Return error objects from server actions.
  • Handle errors in client components.
    "use client";
    
    export default function Form() {
      const [error, setError] = useState<string | null>(null);
      
      async function handleSubmit(formData: FormData) {
        const result = await createPost(formData);
        if (result.error) {
          setError(result.error);
        }
      }
      
      return (
        <form action={handleSubmit}>
          {error && <p>{error}</p>}
        </form>
      );
    }
  • Use useActionState to wire server action errors directly into a form — the action receives prevState as its first argument (React 19 / Next.js 15).
    // actions.ts
    "use server";
    export async function createPost(prevState: unknown, formData: FormData) {
      try {
        await db.post.create({ data: { title: formData.get("title") } });
        return { success: true };
      } catch {
        return { error: "Failed to create post" };
      }
    }
    
    // Form.tsx
    "use client";
    import { useActionState } from "react";
    export default function Form() {
      const [state, action] = useActionState(createPost, null);
      return (
        <form action={action}>
          {state?.error && <p>{state.error}</p>}
          <button type="submit">Create</button>
        </form>
      );
    }
  • Log the full error server-side and return only a safe message to the client — never expose stack traces or database details.
    "use server";
    
    export async function deletePost(id: string) {
      try {
        await db.post.delete({ where: { id } });
        return { success: true };
      } catch (error) {
        console.error("[deletePost] failed:", error); // full error server-side only
        return { error: "Could not delete post" };// safe message to client
      }
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
Next.js Error Handling
Chapter 18 · Page 130
Intermediate

Next.js Error Handling

(continued)

API Route Error Handling

  • Return error responses with appropriate status codes.
    // app/api/posts/[id]/route.ts
    export async function GET(
      request: Request,
      { params }: { params: Promise<{ id: string }> }
    ) {
      const { id } = await params;
      try {
        const post = await getPost(id);
        if (!post) {
          return Response.json(
            { error: "Post not found" },
            { status: 404 }
          );
        }
        return Response.json(post);
      } catch (error) {
        return Response.json(
          { error: "Internal server error" },
          { status: 500 }
        );
      }
    }
  • Always handle errors in API routes explicitly.
  • Return meaningful status codes and error messages.
  • Validate request body fields and return 400 for bad input.
    export async function POST(request: Request) {
      const body = await request.json();
      if (!body.title) {
        return Response.json({ error: "Title is required" }, { status: 400 });
      }
      return Response.json({ ok: true });
    }
  • Return 401 for missing or invalid authentication tokens.
    const token = request.headers.get("authorization");
    if (!token || !isValid(token)) {
      return Response.json({ error: "Unauthorized" }, { status: 401 });
    }
Notes
Useful Cheatsheetsusefulcheatsheets.com
Next.js Error Handling
Chapter 18 · Page 131
Intermediate

Next.js Error Handling

(continued)

Global Error Handling

  • Create app/global-error.tsx to catch errors in the root layout — it replaces the layout entirely, so it must render <html> and <body> tags.

    // app/global-error.tsx — replaces root layout; MUST include <html><body>
    "use client";
    export default function GlobalError({ error, reset }: { error: Error & { digest?: string }; reset: () => void }) {
      return (
        <html>
          <body>
            <h1>Application Error</h1>
            <button onClick={reset}>Try again</button>
          </body>
        </html>
      );
    }
    
  • Regular error.tsx renders inside the existing layout — never add <html> or <body> tags there.

    // app/dashboard/error.tsx — renders inside layout, no html/body tags
    "use client";
    export default function Error({ reset }: { reset: () => void }) {
      return <div><p>Something went wrong.</p><button onClick={reset}>Retry</button></div>;
    }
    
  • Use the error digest to correlate client errors with server log entries.

    export default function Error({ error }: { error: Error & { digest?: string } }) {
      return <p>Error ID: {error.digest}</p>; // matches server-side error log
    }
    
  • Add error monitoring in the useEffect of any error boundary component.

    useEffect(() => {
      Sentry.captureException(error);
      console.error("digest:", error.digest);
    }, [error]);
    
  • Nest error.tsx files at each route segment for targeted recovery — a dashboard error won't break the nav or sidebar.

    app/
      error.tsx           ← catches app-level errors (inside root layout)
      global-error.tsx    ← catches root layout errors (replaces layout)
      dashboard/
        error.tsx         ← catches only dashboard errors
    
Notes
Useful Cheatsheetsusefulcheatsheets.com
Next.js Error Handling
Chapter 18 · Page 132
Intermediate

Next.js Error Handling

(FAQ)

FAQ

error.tsx creates a React error boundary that catches rendering errors in a route segment and its children, while try/catch handles runtime errors in async server components or server actions. Use both: error.tsx for UI recovery, try/catch for data-fetching logic.

Place error.tsx files at each route segment level where you want isolated error recovery — for example, app/dashboard/error.tsx catches errors only in the dashboard segment without breaking the rest of the layout. Nesting them gives users more targeted recovery options.

Return a Response with an appropriate HTTP status code and a JSON body: return Response.json({ error: 'Not found' }, { status: 404 }). Always use 4xx for client errors and 5xx for server errors so consuming clients can handle them correctly.

Wrap your server action logic in a try/catch and return a structured result object like { success: false, error: 'message' } rather than rethrowing, since uncaught server action errors surface as generic failures to the client. Use the error only to inform the UI, never to expose stack traces or DB details.

Add a not-found.tsx file in the app directory (or a specific route segment) and call the notFound() function from 'next/navigation' anywhere in a server component to trigger it. This replaces the default Next.js 404 page for that segment.