L19 · Build & preview · 5 min

Errors your users should never see

In one sentence

Visitors should never see raw stack traces or blank crash screens: your app shows friendly inline messages for expected mistakes, uses not-found.tsx, error.tsx and global-error.tsx safety nets with a “Try again” button for unexpected failures, and gives a short reference ID linked to the server log.

Think of it like this

If a restaurant runs out of soup, the waiter doesn't drop a greasy kitchen clipboard on your table. They politely tell you the soup is gone and offer another dish—or, if the oven broke, give you a receipt number while the kitchen handles it.

How it works

Every web app faces two different kinds of problems: expected errors (things that happen in normal use, like an empty form field, a wrong password or a link to a recipe that doesn't exist) and unexpected errors (something broke on the server or a service didn't answer).

Expected errors are handled right where they happen, without crashing the page. A form returns a clear, calm note next to the field (“Please enter a valid email address”), and a missing item calls notFound() to show your custom not-found.tsx page with a link back home.

Unexpected errors are caught by an Definitionerror boundaryA safety net in your app that catches unexpected errors and shows a friendly message with “Try again”.Open in the glossary →: a safety net built into Next.js. Each main section has an error.tsx file that catches crashes in that area and shows a friendly message with a “Try again” button, while global-error.tsx is the last-resort safety net for the whole app.

Visitors must never see a raw Definitionstack traceThe list of steps that led to an error. Useful for your agent; never shown to your users.Open in the glossary →: it is confusing for people and can leak internal file paths or logic to attackers. Instead, your error page shows a plain message and a short reference ID (such as 7F3K-2Q), while the full Definitionerror messageWhat a program says when something fails. Its first line usually says what; the rest says where.Open in the glossary → and details go to your server DefinitionlogYour app's diary: one line per event. When something breaks, the logs say what happened.Open in the glossary → under that same ID.

Path A · ExpectedInvalid input or missing itemReturned as a friendly inline message on the form, or shown via `not-found.tsx`.
Path B · Unexpectederror.tsx & global-error.tsxError boundaries catch the crash and show a calm message, a “Try again” button, and reference ID `7F3K-2Q`.
Behind the scenesServer log (never the screen)Full details are logged on the server with ID `7F3K-2Q` so your agent can look it up.
FIG. 1 · How your app handles errors safely: expected mistakes show inline hints, unexpected crashes show a friendly boundary with a reference ID, and details stay in the server log.

What it looks like in your project

Right in Task 1 (the app skeleton), your agent adds error.tsx, global-error.tsx and not-found.tsx so your app has safety nets from day one. Whenever it builds a form, it returns validation messages as plain text instead of throwing raw errors.

Copy for your agent

Check that our app has not-found.tsx, error.tsx (with a 'Try again' button) and global-error.tsx, and verify that unexpected errors show a friendly message with a short reference ID while logging details only on the server.

Quick check · 1 question

Why should your live app show a short reference ID (like `7F3K-2Q`) instead of a stack trace when an unexpected error happens?

Go deeper

Next lessonVibe coding vs agentic engineering

Last reviewed Nov 8, 2026