Repository navigation
Description
Problem
A local pnpm test intermittently loses one test file. Its vitest worker dies with exit code 3221226505 (0xC0000409), Windows' fast-fail code, which is also what a Node abort exits with. Every time so far it happened as the worker started packages/settings-window/src/settings-window-server.test.ts (once, settings-window.test.ts):
Error: [vitest-pool]: Worker forks emitted error.
Caused by: Error: Worker exited unexpectedly with exit code 3221226505 during started state while running test file …/packages/settings-window/src/settings-window-server.test.ts
The run exits non-zero, with every other file passing. It is not the dropped worker of #1084 (closed as not planned): that one exited 1. This one has a different exit code and always the same package.
What was measured (2026-10-17, Node v24.15.0, vitest 5.0.3, Windows 11)
- settings-window alone (
pnpm test packages/settings-window/): 13 runs, 0 crashes, 177/177 each time. - Single-worker repro, on
masterat 0268e23: the command below, 3 runs, 2 crashed (both insettings-window-server.test.ts) and 1 passed 1268/1268. - The same shape on the Replay keys: show that a search or long jump is under way, and when a press was held or dropped #1437 branch (the same files plus four more): 1 crash in 4 single-worker runs, and 3 of 3 full
pnpm testruns with one crash each (twicesettings-window-server.test.ts, oncesettings-window.test.ts). - The heap stays at 25 to 35 MB per test in the worker (
--logHeapUsage), so it is not an out-of-memory. - Not reached by the files run before it: settings-window's own dependency closure (app-constants, app-updates, callout-script, logger, settings, callout-settings) imports none of the packages those files test.
- Neither half of the file list, run before settings-window, crashed on its own (one run each). The crash depends on what ran earlier in the same worker, not on one file.
Other trees' full runs the same day (#1426, four runs) did not crash. The cause is not established.
Repro
From the repo root on master, run a few times:
pnpm test packages/icon-composer/src/title-settings.test.ts packages/iracing-actions/src/actions/replay-control/replay-control-dial-surface.test.ts packages/iracing-actions/src/actions/replay-control/replay-control-race-start.test.ts packages/iracing-actions/src/actions/replay-control/replay-control.test.ts packages/iracing-actions/src/actions/replay-markers/replay-markers-dial-surface.test.ts packages/iracing-actions/src/actions/replay-markers/replay-markers.test.ts packages/iracing-actions/src/shared/dial-box.test.ts packages/iracing-actions/src/shared/dial-sim-agnostic.test.ts packages/iracing-actions/src/shared/replay-command-gate.senders.test.ts packages/iracing-actions/src/shared/replay-command-gate.test.ts packages/iracing-actions/src/shared/replay-jump-playback.test.ts packages/settings-window/ --maxWorkers=1Tasks
Cause found 2026-10-20: a Windows-only stack buffer overrun in Node 24.15.0's TCP code, fixed upstream in v24.16.0. Diagnosis and measurements are in the comment below. These tasks replace the original three, which assumed the cause was in our code or in vitest.
- Bump
.nvmrcto 24.21.0 (any version from 24.16.0 works; 24.21.0 matches what Stream Deck now ships), and install it locally. -
.claude/rules/testing.md: one line naming this cause beside the Local test runs intermittently die with a dropped vitest worker, silently losing that file's tests #1084 section, so a3221226505gets anode -vcheck before a bisect. - No
vitest.config.tschange: pool or isolation settings would not help, since the crash happens with no vitest at all.
Affected artifacts
.nvmrc(CI reads it throughnode-version-file; the four ubuntu jobs are unaffected by the bug but move with the pin)..claude/rules/testing.md.
Metadata
Metadata
Assignees
Labels
Projects
- StatusShow more project fieldsDone
Activity
niklam commentedon Oct 20, 2026
Root cause: Node 24.15.0 on Windows, fixed upstream in 24.16.0
The crash is a bug in Node itself, not in our code or in vitest. On Windows, Node 24.15.0 has an intermittent stack buffer overrun in libuv's TCP-connect path, fixed in v24.16.0: nodejs/node#63620 is this bug, and nodejs/node#62561 is the fix. (Corrected 2026-10-21: an earlier version of this comment linked nodejs/node#62991, which reached the same fix second-hand.)
.nvmrchas pinned 24.15.0 since #928 (2026-08-05). CI runs on ubuntu, so it never sees the crash.Measured 2026-10-20 on Windows 11. 24.21.0 and 20.20.2 are the Node binaries Stream Deck installs:
settings-window-server.test.tsalone, vitest, idle machinedist/, no vitesthttp+wsserver doing 3 connect/close cycles, no iRaceDeck codeThree corrections to the issue as filed:
wsclient connect, often the first or second connection in a process.process.abort()exits 134 and prints a native stack. This crash prints nothing, which is why--report-on-fatalerrorwould not catch it. WER records nothing either, because libuv setsSEM_NOGPFAULTERRORBOX.process.dlopentracer, checked to log inside the worker, shows the worker loads no.node.ws' optionalbufferutil/utf-8-validateare not installed.The #1084 dropped workers began after the 24.15.0 pin and were probably the same bug. That is unproven, because no exit code was recorded then.
Tasks (replacing the ones above)
.nvmrcto 24.21.0 (any version from 24.16.0 works; 24.21.0 matches what Stream Deck now ships), and install it locally..claude/rules/testing.md: one line naming this cause, so a3221226505gets anode -vcheck before a bisect.vitest.config.tschange: pool or isolation settings would not help, since the crash happens with no vitest at all.test(scripts): guard the Node pin and the turbo version the inputs te…
docs(rules): path-scope the turbo, Node-crash, board and action-test …