Next.js 'Application error: a server-side exception has occurred' — Find the Real Error (Digest Explained)
Next.js hides the real error in production and shows only a digest. Here is what the digest is, where the full stack trace lives on any host, and how to capture every server error with one instrumentation.ts hook.
Your Next.js app works locally. You deploy it, open a page, and get this instead:
Application error: a server-side exception has occurred (see the server logs for more information). Digest: 1389973523
No message, no stack trace, no file name. Just a number. This is one of the most-reported production errors in the Next.js GitHub issues, and the cause is almost never in the message you can see, because there is no message to see.
Why Next.js hides the error
In production builds, Next.js deliberately omits the error message from anything sent to the browser, so a server-side failure cannot leak internals (database errors, file paths, query text) to your visitors. Instead it attaches a digest: a hash that identifies the error.
The digest is not the error. It is a label that appears in two places:
- On the page the visitor sees.
- Next to the real error and stack trace in your server logs.
The whole debugging job is matching the first to the second.
Step 1: find the digest in your server logs
The full error is printed on the server, not in the browser. Search your logs for the digest string, for example 1389973523.
- Vercel: Project → Logs (runtime logs). Search for the digest or filter to the time of the request. Hobby-plan runtime logs are kept for a short time, so do this soon after the failure (see Vercel log retention).
- Docker:
docker logs <container> - A VPS with pm2:
pm2 logs - Plain
next start: the stdout/stderr of the Node process. - Azure: the app's log stream.
The real cause is often printed on the line just before the generic message. A Prisma error code or a "Ref not found" from a CMS client shows up right there.
Step 2: reproduce it in production mode
Many of these errors only appear after deploying, because next dev is more forgiving. Run what production runs:
next build && next startIf it fails locally in production mode, you can debug it with a normal debugger and no hosting platform involved.
The usual causes
- Missing or wrong environment variables on the server. The most common one. A variable that exists in
.env.localbut was never set in your host's dashboard. - A backend or API URL that only works locally.
localhostURLs, or services not reachable from the deployed environment. - Database or ORM problems. For example Prisma on the edge runtime, or a connection limit.
- Mixing static and dynamic rendering. Reading
searchParamsor cookies in a page that is statically generated. - A bug in one Next.js version. Occasionally a clean redeploy on a newer patch release fixes it.
Step 3: stop doing archaeology — capture every server error
Searching logs works once. The better fix is to record every uncaught server error with its digest at the moment it happens, so the next one takes ten seconds.
Next.js supports an onRequestError hook in instrumentation.ts (Next.js 15 and later). It runs inside your server for every request error, on any host. FlareLog ships a ready-made hook:
// instrumentation.ts (project root, or src/ if you use it)
import { flarelog } from "@flarelog/sdk";
import { createOnRequestError } from "@flarelog/sdk/next";
const logger = flarelog({ apiKey: process.env.FLARELOG_API_KEY });
export const onRequestError = createOnRequestError(logger);Each failure is recorded as an ERROR with:
next.digest, the same number the visitor sees- the route, route type and router kind (App Router or Pages Router)
- the HTTP method and path, without the query string (query strings often carry tokens)
- the full stack trace
Request headers and cookies are never sent. Now, when a user pastes "Digest: 1389973523", you search that number in FlareLog and land on the exact error, with its stack, regardless of where the app is hosted or how long your host keeps logs.
Use the latest @flarelog/sdk; the hook is in the @flarelog/sdk/next entry point, and the Next.js guide has the details.
Two more places to log
error.tsxandglobal-error.tsx. Logerror.digestalongsideerror.messageso client-side boundaries leave a trail too. Remember thatglobal-error.tsxmust render its own<html>and<body>tags.try/catcharound risky server code (data fetching, database calls). Log the real error withconsole.error, so it appears in your logs right next to the digest.
Quick checklist
- Copy the digest from the error page.
- Search your server logs for it (or FlareLog, once the hook is in).
- Read the line above the generic message for the real cause.
- Check env vars on the server, then backend URLs, then database connections.
- Reproduce with
next build && next start. - Add
onRequestErrorso you never have to do steps 1 to 2 by hand again.
Want to try step 6? Start free: 10,000 logs a month, no card. And if you use an AI coding assistant, connect it to your production logs so it can read the error for you.
Never miss an invisible crash again
FlareLog catches the errors Cloudflare can't log. Set up the Tail Worker in 5 minutes and see every crash, timeout, and cost spike in real time.
Start free →