Repository navigation
Run jest with --no-sparkplug to avoid V8 GC segfaults on macOS arm64 - #39081
Merged
Merged
Conversation
Sparkplug is V8's baseline JIT. It leaves a stale near-null pointer in an InternalFrame slot; a later GC conservative stack scan dereferences it and segfaults. Disabling the tier removes the write, so no crash. This kills jest workers with SIGSEGV on macOS arm64 CI before any test body runs, which auto-files an issue against whichever suite happened to be loading. Eight unrelated suites have been hit since April. nodejs/node#62393 — fixed in V8 as shipped in Node 25, not backported to the 24 LTS line our mac agents pin. Remove this once agents move off Node 24. --no-sparkplug can't go in NODE_OPTIONS and .bin/jest is a shell shim that can't take node flags, hence the explicit bin/jest.js path. Workers inherit it because jest-worker forks with execArgv.
Contributor
📋 Code Owners Summary1 file(s) changed, 1 with assigned owners 2 team(s) affected: Owners and Their Files
|
petemill
approved these changes
Aug 13, 2026
petemill
left a comment
Member
There was a problem hiding this comment.
Good find, looks like no downside and we can try to remember to reverse when we get to the next node LTS version after v25.
Collaborator
|
A Storybook has been deployed to preview UI for the latest push |
Collaborator
|
Released in v1.95.70 |
DerrickRice
pushed a commit
that referenced
this pull request
Aug 14, 2026
…39081) Run jest with --no-sparkplug to avoid V8 GC segfaults Sparkplug is V8's baseline JIT. It leaves a stale near-null pointer in an InternalFrame slot; a later GC conservative stack scan dereferences it and segfaults. Disabling the tier removes the write, so no crash. This kills jest workers with SIGSEGV on macOS arm64 CI before any test body runs, which auto-files an issue against whichever suite happened to be loading. Eight unrelated suites have been hit since April. nodejs/node#62393 — fixed in V8 as shipped in Node 25, not backported to the 24 LTS line our mac agents pin. Remove this once agents move off Node 24. --no-sparkplug can't go in NODE_OPTIONS and .bin/jest is a shell shim that can't take node flags, hence the explicit bin/jest.js path. Workers inherit it because jest-worker forks with execArgv.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Jest workers die with
SIGSEGVon macOS arm64 CI before any test body runs. Jest reports this asTest suite failed to runagainst whichever suite happened to be loading, so the bot files an issue blaming a random innocent test. Eight unrelated suites have been hit since April:brave/brave-browser#54805, brave/brave-browser#55563, brave/brave-browser#56561, brave/brave-browser#56673, brave/brave-browser#56744, brave/brave-browser#56847, brave/brave-browser#57864, brave/brave-browser#58046 — all closed as unfixable CI infra.
It isn't infra. It's nodejs/node#62393, from upstream V8 bug 483731079.
Sparkplug is V8's baseline JIT — the cheap tier between the interpreter and the optimizing JITs. It does a fast single-pass bytecode-to-machine-code compile with no optimization. The bug: it leaves a stale near-null pointer in an
InternalFrameslot. A later GC conservative stack scan dereferences that slot and segfaults at address0xe.--no-sparkplugremoves the tier, so nothing writes the bad pointer. Affected code stays interpreted until it's hot enough for TurboFan. No semantic change.Why it surfaced with jest 30:
jest-resolvepullsunrs-resolver, whose NAPI object churn supplies the GC pressure that triggers it.Fixed in V8 as shipped in Node 25. Not backported to the 24 LTS line our mac agents pin (
nvm install v24; 24.19.0 still ships V8 13.6.233.17). Remove this once agents move off Node 24.Two mechanics forced the invocation shape:
--no-sparkplugis rejected inNODE_OPTIONS, and.bin/jestis a shell shim that can't take node flags — hence the explicitbin/jest.jspath. Workers inherit the flag becausejest-workerforks withexecArgv.Applied unconditionally rather than gated to macOS arm64 — it costs nothing where it isn't needed, and a platform check for a free flag is more machinery than it's worth.
test:scriptsalso runs jest but only onc8a.4xlarge(Linux x86), so it's left alone.Timing
Full suite, twice each way, same machine and commit:
--no-sparkplug)Identical pass/fail counts both ways. Flagged runs sit inside the unflagged runs' own variance; the 96.5s outlier was a cold cache. No measurable cost, matching upstream's finding.
Test plan
pnpm run test-unitpasses, same pass/fail counts as beforeprocess.execArgvcontains--no-sparkpluginside a worker passed, then removedpnpm run test-unit -- --verbose --reporters=jest-junit --reporters=default <path>test-unit:walletstill scopes correctlyTest suite failed to run/ SIGSEGV issues