</>CodeWithKarani

Next.js 16.0.1 Fails next build on /_not-found: An Open Regression

Karani GeoffreyKarani Geoffrey7 min read

The pull request was a routine dependency bump: Next.js 15 to 16.0.1, tests green, next dev running happily on every machine. It merged. Then the deploy pipeline ran next build and died while prerendering the not-found page, a route nobody had touched in months. Same code, same lockfile intent, and the only variable that changed was the framework patch version.

This is an open regression in Next.js 16.0.1, tracked upstream, and if you upgrade in CI without running a full production build locally first, your deploy pipeline is where you will discover it. The failure surfaces only during next build, never in next dev, which is exactly the gap that lets a broken upgrade sail through review.

Next.js 16.0.1 can fail next build while prerendering /_not-found with an error about functions being passed to Client Components, on code that built fine on 15.x. It is an open, unresolved regression.

  • Safe path today: pin to the last known-good version you were on (a 15.x release, or a 16 version that built for you) until the tracking issue is resolved.
  • Always run a full next build locally before merging any Next.js version bump. next dev will not catch this class of prerender error.
  • If you must be on 16.0.1, the trigger is a function value reaching a Client Component during static prerender, often via a custom not-found boundary. Audit props passed across the server/client boundary.

The error you will see

The build fails at the prerender step, and the message points at the internal not-found route. The core of it reads:

Error occurred prerendering page "/_not-found".
Error: Functions cannot be passed directly to Client Components unless you
explicitly expose it by marking it with "use server". Or maybe you meant to
call this function rather than return it.
Export encountered an error on /_not-found/page: /_not-found, exiting the build.

The tell-tale signs that you are hitting this specific regression rather than a genuine bug in your own code: it started immediately after moving to 16.0.1, the same tree built on 15.x, and it names /_not-found even if you never wrote a custom not-found component. You can follow the current status on the upstream tracking issue before you spend an afternoon bisecting your own code.

Why it only breaks in next build, never in next dev

This is the part that catches teams out, and it is worth understanding because it generalises to a whole class of App Router failures. next dev renders routes on demand, in a development runtime, when you actually visit them. It is lenient, it does not do the full static export, and it happily runs a lot of code paths that the production build treats strictly.

next build does something next dev never does: it prerenders static routes ahead of time, serialising the React tree so it can be shipped as HTML. Serialisation is where the rule bites. React's server/client boundary forbids passing a raw function as a prop into a Client Component, because a function cannot be serialised and sent to the browser. In development that boundary is enforced loosely; during the static export in next build it is enforced hard, and a function value that slips across the boundary on the not-found path now aborts the whole export.

The practical consequence: a green next dev and passing unit tests tell you nothing about whether the production build works. The only thing that tells you is running the production build.

next dev Renders a route only when visited Boundary enforced loosely Result: looks fine, ships to review next build Prerenders every static route ahead Serialisation boundary enforced hard Result: aborts on /_not-found
The bug lives in the step dev mode skips entirely. That is why review passed and the deploy did not.

The safe path: pin and gate

Step 1: pin back to your last known-good version

The correct immediate move for a production project is to stop being on the broken patch. Do not float the version. In package.json, pin exactly:

{
  "dependencies": {
    "next": "15.5.4"
  }
}

Use whatever version last built cleanly for you; the number above is an example, not a recommendation of a specific release. Pin the exact version with no caret, so a ^ range cannot silently pull 16.0.1 back in on the next install. Then reinstall and confirm:

npm install
npx next --version
# expected: Next.js v15.5.4 (or whichever you pinned)

Step 2: prove the production build works locally

Run the actual production build on your machine before you trust the pin, because this is the command CI runs and the command dev mode never approximates:

next build
# expected: "Compiled successfully" and a route table,
# with no "Error occurred prerendering page" line.

Step 3: make the build a required check, not an afterthought

The deeper fix is process, not a version number. Add next build as a required status check on your default branch so no Next.js bump, or any change, can merge without a passing production build. A minimal CI step:

- name: Production build
  run: npx next build

If you deploy to your own server rather than a managed platform, the walkthrough on shipping to a VPS with GitHub Actions shows where this build gate sits in the pipeline. The rule that saves you here is simple: never let a version bump merge on the strength of next dev and unit tests alone.

If you are stuck on 16.0.1 and need it to build

Sometimes you cannot roll back, because you adopted a 16-only feature. In that case the lead you have is the error itself: a function is reaching a Client Component during the static prerender of the not-found path. Audit the boundary:

  • If you have a custom app/not-found.tsx or a not-found boundary, check every prop it passes to a Client Component. A function passed as a prop (an event handler, a formatter, a callback) is the classic trigger. Move the function definition into the Client Component, or wrap the server-side function with "use server" if it genuinely needs to cross the boundary.
  • Check any shared layout or provider that wraps the not-found route and hands a function down. The error names /_not-found because that is what failed to export, but the offending prop can originate higher in the tree.
  • This is diagnosis, not a guaranteed fix: because the regression is open and unresolved upstream, some triggers are inside framework-generated code you cannot edit. If your audit turns up nothing in your own components, that is a signal the fault is upstream and rolling back is the right call, not more searching.

This is the same category of trap as other App Router build-time surprises, like DynamicServerError opting routes out of static rendering and useSearchParams needing a Suspense boundary: all of them pass in dev and only bite when the production build tries to prerender.

What people get wrong: chasing their own code

The instinct when next build fails is to assume you broke something, and to start bisecting your components. For a regression tied to a specific patch version, that can burn a whole day. The dismantling move is cheap and you should do it first: check out the commit before the version bump, run next build, and confirm it passes. If the only difference between passing and failing is the Next.js version, the bug is not in your code, and no amount of refactoring your components is the right response. Pin back and watch the issue.

The second common mistake is reaching for a config flag to force the build through, or wrapping the build in something that ignores prerender errors. That does not fix anything; it ships a broken not-found route to production and hides the signal that told you the upgrade was not ready.

Verification

You have confirmed the safe state when three things are true: npx next --version reports your pinned known-good version, next build completes locally with no "Error occurred prerendering page" line, and your CI runs that same next build as a required check on the branch. From there, treat the next attempt to move to 16.0.1 (or whatever version claims to fix it) as its own change: bump it on a branch, run the full production build, and only merge if it is green.

When it is still broken

If the build still fails after pinning back, confirm the lockfile actually updated (npm ls next should show only the pinned version, with no stray 16.0.1 pulled in transitively by another package) and delete node_modules and .next before rebuilding to clear a stale cache. If a different route now fails to prerender, you may be looking at a genuine issue in your own code rather than this regression, in which case read the route named in the error and trace the function prop from there. And if you are on a managed platform where the deploy uses a different Next.js version than your local pin, set the version explicitly in the platform's build settings so local and remote agree.

Frequently asked questions

Why does next build fail after upgrading to Next.js 16.0.1 when next dev works?
next dev renders routes on demand and enforces React's server/client boundary loosely, while next build statically prerenders routes ahead of time and enforces it strictly. In 16.0.1 an open regression lets a function value reach a Client Component during the prerender of /_not-found, which aborts the export. dev mode never runs that strict serialisation step, so it looks fine.
What does 'Error occurred prerendering page /_not-found' mean in Next.js 16?
It means the static export of the internal not-found route failed, in this case because a function was passed into a Client Component during prerendering. If it started right after moving to 16.0.1, the same tree built on 15.x, and you never wrote a custom not-found component, you are almost certainly hitting the known open regression rather than a bug in your own code.
What is the safe way to handle the Next.js 16.0.1 build regression?
Pin next to the exact last version that built cleanly for you, with no caret so a range cannot pull 16.0.1 back in, then run next build locally to confirm it passes. Add next build as a required CI status check so no version bump can merge without a passing production build. Retry 16.0.1 as its own gated change once the upstream issue is resolved.
Should I use a flag to force the Next.js build past the prerender error?
No. Forcing or ignoring the prerender error ships a broken not-found route to production and hides the signal that the upgrade is not ready. The correct response is to pin back to a known-good version and follow the upstream tracking issue, or, if you are stuck on 16, audit the not-found route's props for a function crossing into a Client Component.
#Next.js#React#Build#Prerendering#CI/CD
Keep reading

Related articles