You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
TL;DR: During dev with @cloudflare/vite-plugin, the workerd isolate's heap grows on every server-file edit (module graph re-evaluation). Large apps reach V8's default ~1.4 GB heap limit within a normal editing session; workerd then aborts and — since Miniflare has no crash recovery (#13045) — every request returns the opaque fetch failed until the dev server is manually restarted. There is currently no way to raise the limit: the workerd config supports v8Flags but Miniflare never populates it, and NODE_OPTIONS only affects the Node process. Minimal framework-free repro below; one-line mitigation in #14702.
What happens
V8 fatal error; location = Reached heap limit; message = : allocation failed: JavaScript heap out of memory
*** Received signal #6: Aborted
stack: .../node_modules/@cloudflare/workerd-linux-64/bin/workerd@...
then, for every subsequent request:
fetch failed
at Object.processResponse (node_modules/miniflare/node_modules/undici/lib/web/fetch/index.js:237:16)
at async _Miniflare.dispatchFetch (node_modules/miniflare/dist/src/index.js:91788:22)
at async @cloudflare/vite-plugin/dist/index.mjs:37094:19
We believe this is widely misdiagnosed: the V8 fatal error is printed once, then buried under thousands of fetch failed traces that look like a network problem (or like the fixed #13013). We hit it daily on Windows 11 and Linux before diagnosing it.
Minimal reproduction
https://github.com/sipixer/vite-plugin-cloudflare-heap-repro — plain fetch handler + generated modules importing one hub.ts, no framework. Append one line to hub.ts, request, measure workerd RSS, repeat. Reproduces on latest (@cloudflare/vite-plugin@1.45.0 / miniflare@4.20260710.0):
Each edit transiently costs ~5× the re-evaluated source in heap (~50 MB for a 10 MB graph).
Post-full-GC floor climbs (372 → 866 MB over 55 edits); with a 22 MB graph, repeated runaway phases where 6–7 consecutive edits reclaim nothing (880 → 1540 MB RSS).
Our real app (TanStack Start SSR, ~850 MB baseline after first render) crosses the limit in 30–60 edits: the crash log shows back-to-back last-resort Mark-Compact 1401.2 → 1401.2 MB freeing zero bytes before the abort.
All numbers are workerd RSS (/proc/<pid>/status VmRSS), requests are GET / (SSR):
Scenario
Result
Baseline after first SSR render
~850 MB
10 requests, no edits
+2 MB total
10 server-file edits (append one comment line to a widely-imported module, then 1 request each)
+10–12 MB per edit (846 → 928 MB)
Organic crash (real editing session)
Reached heap limit at V8 heap 1401 MB, ~31 min after startup
After the crash
3571 consecutive fetch failed (500 in ~2 ms); only a full dev-server restart recovers
Positive control: injecting v8Flags: ["--max-old-space-size=256"] into the generated config makes workerd OOM at exactly 255.9 MB on first render — the limit is the V8 default, and raising it works: with --max-old-space-size=4096, 70 edit cycles + 238 concurrent requests completed with zero failures where the default config died after 30–60 edits.
Plain .ts edits do not restart workerd (in-place HMR through the runner Durable Object), so this is isolate heap growth, not process churn. Environment: wrangler 4.77.0, TanStack Start 1.167.8, rolldown-vite 7.3.1, Node 24, reproduced on Debian 13 and Windows 11.
TL;DR: During dev with
@cloudflare/vite-plugin, the workerd isolate's heap grows on every server-file edit (module graph re-evaluation). Large apps reach V8's default ~1.4 GB heap limit within a normal editing session; workerd then aborts and — since Miniflare has no crash recovery (#13045) — every request returns the opaquefetch faileduntil the dev server is manually restarted. There is currently no way to raise the limit: the workerd config supportsv8Flagsbut Miniflare never populates it, andNODE_OPTIONSonly affects the Node process. Minimal framework-free repro below; one-line mitigation in #14702.What happens
then, for every subsequent request:
We believe this is widely misdiagnosed: the
V8 fatal erroris printed once, then buried under thousands offetch failedtraces that look like a network problem (or like the fixed #13013). We hit it daily on Windows 11 and Linux before diagnosing it.Minimal reproduction
https://github.com/sipixer/vite-plugin-cloudflare-heap-repro — plain
fetchhandler + generated modules importing onehub.ts, no framework. Append one line tohub.ts, request, measure workerd RSS, repeat. Reproduces on latest (@cloudflare/vite-plugin@1.45.0/miniflare@4.20260710.0):Mark-Compact 1401.2 → 1401.2 MBfreeing zero bytes before the abort.Detailed measurements (real app, vite-plugin 1.44.0 / miniflare 4.20260708.1)
All numbers are workerd RSS (
/proc/<pid>/status VmRSS), requests areGET /(SSR):Reached heap limitat V8 heap 1401 MB, ~31 min after startupfetch failed(500 in ~2 ms); only a full dev-server restart recoversPositive control: injecting
v8Flags: ["--max-old-space-size=256"]into the generated config makes workerd OOM at exactly 255.9 MB on first render — the limit is the V8 default, and raising it works: with--max-old-space-size=4096, 70 edit cycles + 238 concurrent requests completed with zero failures where the default config died after 30–60 edits.Plain
.tsedits do not restart workerd (in-place HMR through the runner Durable Object), so this is isolate heap growth, not process churn. Environment:wrangler4.77.0, TanStack Start 1.167.8,rolldown-vite7.3.1, Node 24, reproduced on Debian 13 and Windows 11.Suggested fixes
v8Flags— [miniflare] Support workerd V8 flags via MINIFLARE_WORKERD_V8_FLAGS environment variable #14702 adds aMINIFLARE_WORKERD_V8_FLAGSenv passthrough (mirroringMINIFLARE_WORKERD_AUTOGATES, Support autogates viaMINIFLARE_WORKERD_AUTOGATESenv var #8431). One line, unblocks anyone hitting this today.dispatchFetchfails after the runtime process exited, surface "workerd crashed — restart the dev server" instead of the bare undicifetch failed.Workaround for anyone hitting this today
Patch
miniflare(viabun patch/patch-package) to add one line in#assembleConfig's return value:then run dev with
MINIFLARE_WORKERD_V8_FLAGS=--max-old-space-size=4096.