Skip to content

Commit a143282

Browse files
nathanschramclaude
andauthored
fix(patches): return empty object for unhandled manifests in loadManifest (#1151)
* fix: return empty object for unhandled manifests in loadManifest/evalManifest * chore: add changeset for load-manifest fix * fix: handle only known optional manifests instead of blanket catch-all 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. * fix: handle extensionless manifests and add prefetch-hints - 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> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent bf33735 commit a143282

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
---
2+
"@opennextjs/cloudflare": patch
3+
---
4+
5+
fix: handle known optional manifests gracefully in loadManifest/evalManifest patches
6+
7+
Next.js loads certain manifests with `handleMissing: true` (returning `{}` when the file doesn't
8+
exist). The adapter's build-time glob scan doesn't find these files when they're conditionally
9+
generated, so the patched function threw at runtime, crashing dynamic routes with 500.
10+
11+
Instead of a blanket catch-all, handle only the specific optional manifests from Next.js
12+
`route-module.ts`:
13+
14+
- `react-loadable-manifest` (Turbopack per-route, not all routes have dynamic imports)
15+
- `subresource-integrity-manifest` (only when `experimental.sri` configured)
16+
- `server-reference-manifest` (App Router only)
17+
- `dynamic-css-manifest` (Pages Router + Webpack only)
18+
- `fallback-build-manifest` (only for `/_error` page)
19+
- `prefetch-hints` (new in Next.js 16.2)
20+
- `_client-reference-manifest.js` (optional for static metadata routes, evalManifest)
21+
22+
Manifest matching strips `.json` before comparison since some Next.js constants omit
23+
the extension (`SUBRESOURCE_INTEGRITY_MANIFEST`, `DYNAMIC_CSS_MANIFEST`, etc.).
24+
25+
Unknown manifests still throw to surface genuine errors.
26+
27+
Fixes #1141.

packages/cloudflare/src/cli/build/patches/plugins/load-manifest.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,23 @@ function loadManifest($PATH, $$$ARGS) {
6666
return process.env.NEXT_BUILD_ID;
6767
}
6868
${returnManifests}
69+
// Known optional manifests \u2014 Next.js loads these with handleMissing: true
70+
// (see vercel/next.js packages/next/src/server/route-modules/route-module.ts).
71+
// Return {} to match Next.js behaviour instead of crashing the worker.
72+
// Note: Some manifest constants in Next.js omit the .json extension
73+
// (e.g. SUBRESOURCE_INTEGRITY_MANIFEST, DYNAMIC_CSS_MANIFEST), so we
74+
// strip .json before matching to handle both forms.
75+
{
76+
const p = $PATH.replace(/\\.json$/, "");
77+
if (p.endsWith("react-loadable-manifest") ||
78+
p.endsWith("subresource-integrity-manifest") ||
79+
p.endsWith("server-reference-manifest") ||
80+
p.endsWith("dynamic-css-manifest") ||
81+
p.endsWith("fallback-build-manifest") ||
82+
p.endsWith("prefetch-hints")) {
83+
return {};
84+
}
85+
}
6986
throw new Error(\`Unexpected loadManifest(\${$PATH}) call!\`);
7087
}`,
7188
} satisfies RuleConfig;
@@ -110,6 +127,11 @@ function evalManifest($PATH, $$$ARGS) {
110127
function evalManifest($PATH, $$$ARGS) {
111128
$PATH = $PATH.replaceAll(${JSON.stringify(sep)}, ${JSON.stringify(posix.sep)});
112129
${returnManifests}
130+
// client-reference-manifest is optional for static metadata routes
131+
// (see vercel/next.js route-module.ts, loaded with handleMissing: true)
132+
if ($PATH.endsWith("_client-reference-manifest.js")) {
133+
return { __RSC_MANIFEST: {} };
134+
}
113135
throw new Error(\`Unexpected evalManifest(\${$PATH}) call!\`);
114136
}`,
115137
} satisfies RuleConfig;

0 commit comments

Comments
 (0)