Windows: vitest pool worker killed by a V8 compiler-zone OOM, invisible in the JSON report
Summary
Running the full suite on Windows kills a vitest pool worker with a V8 compiler-zone OOM. It has reproduced across separate runs with a byte-identical native stack. The crash is not visible in the JSON report — a dying worker is not a test failure, so it appears in no testResults entry and vitest recycles the worker and continues. A run can therefore report an internally consistent pass/fail summary while a worker was in fact killed.
This is a Zone OOM, not a JS heap OOM, so --max-old-space-size does not reach it.
The crash
#
# Fatal process out of memory: Zone
#
----- Native stack trace -----
1: 00007FF6F95A495D node::MultiIsolatePlatform::DisposeIsolate+5341
2: 00007FF6FAA12006 v8::base::FatalOOM+54
3: 00007FF6FA29F5E5 v8::Function::NewInstance+245
4: 00007FF6F9C19576 v8::SnapshotCreator::GetIsolate+56566
5: 00007FF6FAE93F5A v8::platform::DelayedTaskQueue::Terminate+1698970
6: 00007FF6FAE9364B v8::platform::DelayedTaskQueue::Terminate+1696651
7: 00007FF6FAE92B0D v8::platform::DelayedTaskQueue::Terminate+1693773
8: 00007FF6FAE925E4 v8::platform::DelayedTaskQueue::Terminate+1692452
9: 00007FF6FAE91B71 v8::platform::DelayedTaskQueue::Terminate+1689777
10: 00007FF6FAE918CF v8::platform::DelayedTaskQueue::Terminate+1689103
11: 00007FF6FAC9F686 v8::base::DiyFp::Multiply+414934
12: 00007FF6FAC9E3A0 v8::base::DiyFp::Multiply+410096
13: 00007FF6FAA722EB v8::internal::compiler::CompilationDependencies::FieldTypeDependencyOffTheRecord+192907
14: 00007FF6F9912F56 DH_get0_engine+658470
15: 00007FF6F990E693 DH_get0_engine+639843
16: 00007FF6F990DF79 DH_get0_engine+638025
17: 00007FF6FAA8519F v8::platform::DefaultJobHandle::UpdatePriority+591
18: 00007FF6F95A081E node::GetNodeReport+90430
19: 00007FF6FA2F46D6 uv_thread_detach+150
20: 00007FF6FB55A033 v8::base::UnsignedDivisionByConstant<unsigned __int64>+2907267
21: 00007FF9B23DCCB7 BaseThreadInitThunk+23
22: 00007FF9B2E0AD6C RtlUserThreadStart+44
Frames 13 and 17 (internal::compiler::CompilationDependencies, platform::DefaultJobHandle::UpdatePriority) put this on a background optimizing-compiler job thread, which is why the exhausted arena is a compiler Zone rather than the JS heap.
The same stderr also carries, from tinypool:
Error: Worker exited unexpectedly
❯ ChildProcess.onUnexpectedExit node_modules/tinypool/dist/index.js:118:30
❯ ChildProcess.emit node:events:521:24
❯ ChildProcess._handle.onexit node:internal/child_process:295:12
Reproduction
Two full-suite runs on the same host, hours apart, on different commits, produced identical stacks. Both were vitest run --maxWorkers=8 --minWorkers=1 under Node, driven by automation that preserves each run's stderr.
The second occurrence is the more informative one. That run reported 4163 passed / 59 failed — a report with no structural sign of a crash — while a worker had been killed by this OOM. Of its 59 failures, 58 were timeouts and one was a known wall-clock assertion; none corresponded to the crash, because none could.
Why this is worth fixing separately from the timeout noise
I originally filed #1773 attributing this host's unstable failure counts to machine load. That attribution was not controlled and I have corrected it there. Relevant to this issue: the compiler-zone OOM recurred after antivirus exclusions were partially applied, so unlike the timeout class it is not plausibly a scanning artifact. It is a distinct failure mode that survived the intervention which removed the timeouts.
The reporting gap is the part I would most like addressed:
- The JSON report cannot be used to establish that a run was healthy. I classified the second run from
vitest.jsonalone and concluded it was clean apart from timeouts; the fatal crash was in stderr the whole time. - Combined with the inverse case in #1773 — a fully green report (
success: true, 0 failed, 4396 passed) that still exits 1 — the exit code and the report disagree in both directions. Automation cannot currently trust either one alone.
Environment
- Windows 11 Pro (10.0.26200), 32 logical cores, 128 GB RAM
- Node v26.8.1 (not Bun)
vitest run --maxWorkers=8 --minWorkers=1, JSON + default reporters
Possible directions
I have not diagnosed the allocation that exhausts the zone, so this is a report rather than a fix, but a few things would each help independently:
- Surfacing worker deaths in the JSON report, or at minimum a non-zero structured signal distinguishable from ordinary test failure, so a crashed run cannot read as healthy.
- Whether a smaller
maxWorkersorpoolOptions.forks.maxForkson Windows changes reproduction — worth knowing, though note that serializing the suite did not change the timeout class on this host, so I would not assume it helps here either. - Whether any test compiles or evaluates unusually large generated sources; a compiler-zone OOM points at optimizing compilation, not at retained heap.
Happy to attach the complete stderr from either run, and the JSON report from the run that looked clean.
Source: colbymchenry/codegraph