Skip to content

fix(ci): pin Node to 24.18.0 so better-sqlite3 stops aborting test workers - #58

Merged
woodenconsulting merged 1 commit into
mainfrom
fix/ci-worker-crashes
Aug 19, 2026
Merged

fix(ci): pin Node to 24.18.0 so better-sqlite3 stops aborting test workers#58
woodenconsulting merged 1 commit into
mainfrom
fix/ci-worker-crashes

Conversation

@woodenconsulting

@woodenconsulting woodenconsulting commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

What was broken

CI has been failing on main since the runner image moved from 20260720 to 20260810, with no code change to explain it. Three to six vitest workers die mid-run, taking their whole test files with them, so coverage lands ~1-2 points under the gate. Reproduced on an unmodified-main PR, so it was never caused by a feature branch.

Root cause

The floating node-version: '24' pin moved from 24.18.0 to 24.19.0. That release shipped nodejs/node#63642 ("src: add cleanup hooks to node::ObjectWrap"), which changes the contract for NAN-style ObjectWrap addons. better-sqlite3 is one, and its Statement destructor now calls RemoveEnvironmentCleanupHook after the Environment is already gone:

#  Assertion failed: (env) != nullptr
 1: node::Assert(node::AssertionInfo const&)
 2: node::RemoveEnvironmentCleanupHook(v8::Isolate*, void (*)(void*), void*)
 3: Statement::~Statement()  [better_sqlite3.node]

The process dies with SIGABRT. Tinypool reports only Worker exited unexpectedly, which is why this looked like flakiness rather than a crash.

How it was confirmed

Reproduced in a container matching the runner (Ubuntu, non-root, 4 CPUs, pnpm 10.34.5), then isolated by changing one variable:

Node Workers killed Aborts Files
24.19.0 4-6 per run yes 188/193
24.18.0 0 0 193/193

Ruled out along the way: OOM (cgroup oom_kill 0, peak 1.75 GB against a 16 GB limit), the runner's kernel log (no OOM or segfault entries), teardown timeouts (still failed at 60s), and any kill call in our own code (there are none in the test suite).

The fix

Pin Node to 24.18.0 across all six workflows through a single NODE_VERSION constant, so the version can't drift again one workflow at a time. Revisit when better-sqlite3 adapts to the new hook contract.

Note on the shipped daemon

build-sidecar.mjs targets node24 for the packaged binary, which is the same floating major. If pkg's Node 24 base moves past 24.19.0, the shipped daemon could hit this abort at shutdown. Worth a follow-up; out of scope here.

🤖 Generated with Claude Code

@woodenconsulting woodenconsulting changed the title ci: unbreak the quality job's vitest worker crashes fix(ci): pin Node to 24.18.0 so better-sqlite3 stops aborting test workers Aug 19, 2026
…rkers

- pin every workflow's Node to 24.18.0 through a single NODE_VERSION constant, replacing the floating '24' that silently moved to 24.19.0
- Node 24.19.0 shipped nodejs/node#63642, which makes better-sqlite3's Statement destructor call RemoveEnvironmentCleanupHook after the environment is gone; the resulting assertion killed vitest workers with SIGABRT, dropped whole test files from the run, and failed the coverage gate with no code change to explain it

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@woodenconsulting
woodenconsulting merged commit 51ab471 into main Aug 19, 2026
6 checks passed
@woodenconsulting
woodenconsulting deleted the fix/ci-worker-crashes branch August 19, 2026 17:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant