Skip to content

Local test runs lose a settings-window test file to a vitest worker that aborts (exit 0xC0000409) #1444

Closed

Description

@niklam

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 master at 0268e23: the command below, 3 runs, 2 crashed (both in settings-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 test runs with one crash each (twice settings-window-server.test.ts, once settings-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=1

Tasks

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.

Affected artifacts

  • .nvmrc (CI reads it through node-version-file; the four ubuntu jobs are unaffected by the bug but move with the pin).
  • .claude/rules/testing.md.

Activity

  1. added
    kind: dev-experienceThe harness, build, CI, rules and tooling for whoever works on the repo
    area: settingsSettings window, Property Inspectors, global settings
    on Oct 17, 2026
  2. niklam commented on Oct 20, 2026

    @niklam
    OwnerAuthor

    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.) .nvmrc has 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:

    Run 24.15.0 24.21.0 20.20.2
    settings-window-server.test.ts alone, vitest, idle machine 4/30 crashed 0/40 not run
    The file's scenarios replayed in plain Node against the built dist/, no vitest 27/600 0/600 0/600
    A bare http + ws server doing 3 connect/close cycles, no iRaceDeck code 3/600 0/600 0/600

    Three corrections to the issue as filed:

    • It does not depend on earlier files. The file crashes alone (4/30). It crashes most in full runs because it is the suite's only heavy loopback-WebSocket user. The crash hits during a ws client connect, often the first or second connection in a process.
    • It is not a Node abort. In a forked child, process.abort() exits 134 and prints a native stack. This crash prints nothing, which is why --report-on-fatalerror would not catch it. WER records nothing either, because libuv sets SEM_NOGPFAULTERRORBOX.
    • It is not vitest or a native addon. The plain-Node replay crashes the same way with and without an IPC channel. A process.dlopen tracer, checked to log inside the worker, shows the worker loads no .node. ws' optional bufferutil / utf-8-validate are 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)

    • Bump .nvmrc to 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 a 3221226505 gets a node -v check before a bisect.
    • No vitest.config.ts change: pool or isolation settings would not help, since the crash happens with no vitest at all.
  3. self-assigned this
    on Oct 21, 2026
  4. added this to the 3.7.0 milestone on Oct 21, 2026
  5. moved this from Backlog to In progress in iRaceDeck Roadmapon Oct 21, 2026
  6. moved this from In progress to Testing in iRaceDeck Roadmapon Oct 21, 2026
  7. moved this from Testing to Done in iRaceDeck Roadmapon Oct 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area: settingsSettings window, Property Inspectors, global settingskind: dev-experienceThe harness, build, CI, rules and tooling for whoever works on the repo

Projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions