Skip to content

fix(patches): return empty object for unhandled manifests in loadManifest#1151

Merged
conico974 merged 4 commits intoopennextjs:mainfrom
nathanschram:fix/load-manifest-graceful-fallback
Mar 21, 2026
Merged

fix(patches): return empty object for unhandled manifests in loadManifest#1151
conico974 merged 4 commits intoopennextjs:mainfrom
nathanschram:fix/load-manifest-graceful-fallback

Conversation

@nathanschram
Copy link
Copy Markdown
Contributor

Summary

  • Return {} instead of throwing for manifest paths not found during the build-time glob scan in loadManifest() and evalManifest()
  • Handles Next.js 16.2.0-canary.53+ which introduces new loadManifest() calls for optional/phase-dependent manifests

Problem

Next.js canary adds loadManifest() calls for:

  1. subresource-integrity-manifest.json - only generated when experimental.sri is configured, but loaded unconditionally
  2. Per-route react-loadable-manifest.json - generated by Turbopack, possibly in a different build phase

The adapter's build-time glob scan doesn't find these files, so the patched function throws at runtime, crashing all dynamic routes with 500.

Fix

Replace the throw new Error('Unexpected loadManifest...') fallback with return {}. This follows the same defensive pattern used by other adapter plugins (instrumentation.ts, find-dir.ts) that return safe defaults for missing files.

Test plan

  • Build a Next.js app with next@canary (16.2.0-canary.53+) using @opennextjs/cloudflare
  • Verify dynamic/SSR routes no longer return 500
  • Verify existing manifests still load correctly (app-manifest, build-manifest, etc.)
  • Verify SRI works correctly when experimental.sri IS configured

Fixes #1141

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Feb 25, 2026

🦋 Changeset detected

Latest commit: a695016

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@opennextjs/cloudflare Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@nathanschram
Copy link
Copy Markdown
Contributor Author

Hey @vicb - just wanted to check in on this. No rush at all, I know you're probably busy. Just wanted to make sure the approach looks reasonable to you, or if you'd prefer I take it in a different direction. Happy to adjust anything.

@Rovak
Copy link
Copy Markdown

Rovak commented Mar 19, 2026

Can confirm that is working for me in production after copying this patch into the project using pnpm patch

@bonadio
Copy link
Copy Markdown

bonadio commented Mar 20, 2026

Need this fix too.
Thanks

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Mar 20, 2026

Open in StackBlitz

npm i https://pkg.pr.new/@opennextjs/cloudflare@1151

commit: a695016

@sommeeeer
Copy link
Copy Markdown
Collaborator

sommeeeer commented Mar 20, 2026

LGTM, until this is merged you can use npm i https://pkg.pr.new/@opennextjs/cloudflare@1151.

// This handles optional manifests (e.g. subresource-integrity-manifest.json when
// experimental.sri is not configured) and manifests generated in a different build
// phase (e.g. per-route react-loadable-manifest.json with Turbopack).
return {};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is the right solution, this will just hide other potential errors, if we know the one that could be null, that's the one we should return an empty object, not everything

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call - updated to handle only the specific manifests that Next.js loads with handleMissing: true (traced through route-module.ts in vercel/next.js).

The five optional manifests for loadManifest:

  • react-loadable-manifest.json - Turbopack per-route, not all routes have dynamic imports
  • subresource-integrity-manifest.json - only when experimental.sri configured
  • server-reference-manifest.json - App Router only, Pages Router never generates
  • dynamic-css-manifest.json - Pages Router + Webpack only
  • fallback-build-manifest.json - only for /_error page

Everything else still throws. Same approach for evalManifest - only _client-reference-manifest.js gets a safe default ({ __RSC_MANIFEST: {} }) since it's optional for static metadata routes.

$PATH = $PATH.replaceAll(${JSON.stringify(sep)}, ${JSON.stringify(posix.sep)});
${returnManifests}
throw new Error(\`Unexpected evalManifest(\${$PATH}) call!\`);
return {};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed - evalManifest now only handles _client-reference-manifest.js (optional for static metadata routes per route-module.ts line 343). Returns { __RSC_MANIFEST: {} } as the safe default structure. Everything else still throws.

Address review feedback from @conico974 — instead of returning {} for all
unknown manifests (which would hide genuine errors), only handle the specific
manifests that Next.js loads with handleMissing: true.

loadManifest optional manifests (from vercel/next.js route-module.ts):
- react-loadable-manifest.json (Turbopack per-route)
- subresource-integrity-manifest.json (experimental.sri)
- server-reference-manifest.json (App Router only)
- dynamic-css-manifest.json (Pages Router + Webpack only)
- fallback-build-manifest.json (/_error page only)

evalManifest optional manifests:
- _client-reference-manifest.js (static metadata routes)

Everything else still throws to surface genuine errors.
@bonadio
Copy link
Copy Markdown

bonadio commented Mar 20, 2026

LGTM, until this is merged you can use npm i https://pkg.pr.new/@opennextjs/cloudflare@1151.

This did not work for me, trying to run next 16.2 still receives "Unexpected loadManifest(/.next/server/prefetch-hints.json) call!" running with wrangler dev locally

@matthewvolk
Copy link
Copy Markdown
Contributor

matthewvolk commented Mar 20, 2026

Hey @nathanschram — we've been testing Next.js 16.2.0 (stable, not canary) on Cloudflare Workers and can confirm this PR is needed alongside #1160 for things to work.

We found one issue during testing (after manually applying the patch from this PR locally): some manifests are requested without the .json extension, so the $PATH.endsWith("...-manifest.json") checks don't match them.

Root cause

Next.js defines some manifest constants without .json:

  • SUBRESOURCE_INTEGRITY_MANIFEST = "subresource-integrity-manifest" (source)
  • DYNAMIC_CSS_MANIFEST = "dynamic-css-manifest" (same file)

When loadManifest() is called with these constants, the path ends up as e.g. /.next/server/dynamic-css-manifest — no .json extension.

My suggestion for this PR

For each manifest in the fallback list, check both with and without .json:

$PATH.endsWith("dynamic-css-manifest.json") || $PATH.endsWith("dynamic-css-manifest")

Or strip .json from the path before matching:

const normalizedPath = $PATH.replace(/\.json$/, "");
if (normalizedPath.endsWith("dynamic-css-manifest")) return {};

After manually applying (locally) #1160 + this PR + the extensionless fix above, I can confirm that our Next.js 16.2.0 app renders successfully on Cloudflare Workers (for Platforms, in our case):

next-16-2-0-running-after-manual-patches

Happy to help with the fix or open a follow-up PR if that's easier. Thanks for this PR!

Copy link
Copy Markdown
Collaborator

@conico974 conico974 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM Thanks for the fix

@conico974
Copy link
Copy Markdown
Collaborator

@nathanschram Could You fix the prettier issue please ?

- Fix prettier formatting in changeset
- Strip .json extension before matching optional manifests since Next.js
  defines some constants without it (SUBRESOURCE_INTEGRITY_MANIFEST,
  DYNAMIC_CSS_MANIFEST, SERVER_REFERENCE_MANIFEST)
- Add prefetch-hints to the optional manifest list (new in Next.js 16.2)
- All 236 tests pass, tsc clean, prettier clean

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@nathanschram
Copy link
Copy Markdown
Contributor Author

@conico974 Prettier issue should be fixed now - sorry about that.

@matthewvolk Great catch on the extensionless manifests - I've updated the matching to strip .json before comparison, so it now handles both dynamic-css-manifest and dynamic-css-manifest.json. Verified against the Next.js constants in shared/lib/constants.ts where SUBRESOURCE_INTEGRITY_MANIFEST, DYNAMIC_CSS_MANIFEST, and SERVER_REFERENCE_MANIFEST are all defined without the extension.

@bonadio Added prefetch-hints to the optional manifest list as well - it's a new constant (PREFETCH_HINTS = 'prefetch-hints.json') in Next.js 16.2.

Summary of changes in the latest push:

  • Prettier fix on changeset
  • Extensionless manifest matching (strips .json before checking)
  • prefetch-hints added to the optional list
  • All 236 tests pass, tsc clean

@conico974 conico974 merged commit a143282 into opennextjs:main Mar 21, 2026
7 checks passed
conico974 added a commit to opennextjs/adapters-api that referenced this pull request Mar 21, 2026
icanvardar added a commit to heycupola/relic that referenced this pull request Mar 23, 2026
Next.js 16.2.0 introduced prefetch-hints.json which crashes on
Cloudflare Workers with @opennextjs/cloudflare@1.17.1. The fix
(opennextjs/opennextjs-cloudflare#1151) is merged but not yet
released to npm.
icanvardar added a commit to heycupola/relic that referenced this pull request Mar 23, 2026
Next.js 16.2.0 introduced prefetch-hints.json which crashes on
Cloudflare Workers with @opennextjs/cloudflare@1.17.1. The fix
(opennextjs/opennextjs-cloudflare#1151) is merged but not yet
released to npm.
conico974 added a commit to opennextjs/adapters-api that referenced this pull request Mar 29, 2026
* ppr support

* fix experimental in aws

* port opennextjs/opennextjs-aws#1107

* add support for segment in PPR

* fix composable cache

* fix experimental test

* make PPR work in cloudflare

* bump to 16.2.1

* port pr opennextjs/opennextjs-cloudflare#1151

* fix composable cache cloudflare

* fix: update Open-Graph tests to skip and assert cache behavior

* format

* fix: update revalidate tag test to assert "MISS" for x-nextjs-cache header

* enable experimental for cf

* fix: rename build:worker script to build:worker:cf for clarity

* fix: skip test for cached fetch in ISR due to unresolved issues

* basic review

* review
linyiru added a commit to solcreek/adapter-creek that referenced this pull request Apr 10, 2026
Two changes pulled from opennextjs/opennextjs-cloudflare#1151 and #1160:

1. load-manifest.js: when a manifest lookup misses, fall back to {} for
   the known optional manifests Next.js loads with handleMissing: true
   (react-loadable, subresource-integrity, server-reference,
   dynamic-css, fallback-build, prefetch-hints, _client-reference).
   Unknown manifests still throw to surface real bugs. Without this,
   dynamic routes 500 when the build-time glob scan misses a
   conditionally generated manifest.

2. package.json: bump min Next.js to 16.2.3 (CVE-2026-23869).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
linyiru added a commit to solcreek/adapter-creek that referenced this pull request Apr 10, 2026
Two changes pulled from opennextjs/opennextjs-cloudflare#1151 and #1160:

1. load-manifest.js: when a manifest lookup misses, fall back to {} for
   the known optional manifests Next.js loads with handleMissing: true
   (react-loadable, subresource-integrity, server-reference,
   dynamic-css, fallback-build, prefetch-hints, _client-reference).
   Unknown manifests still throw to surface real bugs. Without this,
   dynamic routes 500 when the build-time glob scan misses a
   conditionally generated manifest.

2. package.json: bump min Next.js to 16.2.3 (CVE-2026-23869).
ColeMurray pushed a commit to ColeMurray/background-agents that referenced this pull request Apr 20, 2026
## Summary
- bump `@opennextjs/cloudflare` from `1.17.1` to `1.19.1` and pin the
version in `packages/web/package.json`
- pick up the OpenNext Cloudflare fixes for the Next.js 16.2
`prefetch-hints.json` runtime crash I hit during deployment after
updating to the latest version of open-inspect
- keep Open-Inspect users on a known-good adapter version via the repo
lockfile instead of relying on whatever version `npx` might otherwise
fetch

## Why
I hit a production failure after deploying the Cloudflare web app with
Next `16.2.3`:

```text
Error 1101
Unexpected loadManifest(/.next/server/prefetch-hints.json) call!
```

Root cause: Next 16.2 introduced `prefetch-hints.json`, but
`@opennextjs/cloudflare@1.17.1` did not inline or gracefully handle that
manifest in its patched `loadManifest()` runtime shim.

Upstream references:
- opennextjs/opennextjs-cloudflare#1157
- opennextjs/opennextjs-cloudflare#1160
- opennextjs/opennextjs-cloudflare#1151

`1.19.1` includes the manifest-handling fixes released after `1.17.1`,
so this avoids the Cloudflare worker startup crash without keeping our
app pinned to an older Next version.

## Validation
- verified locally that the failure reproduces with `next@16.2.3` +
`@opennextjs/cloudflare@1.17.1`
- verified a minimal standalone repro serves successfully after
upgrading the adapter to `@opennextjs/cloudflare@1.17.3+`

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->

## Summary by CodeRabbit

* **Chores**
* Updated development dependency version for improved build tooling
compatibility.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Unexpected loadManifest calls for new manifest files introduced in Next.js 16.2.0-canary

6 participants