Skip to content

Run jest with --no-sparkplug to avoid V8 GC segfaults on macOS arm64 - #39081

Merged
bbondy merged 1 commit into
masterfrom
jest-no-sparkplug-macos-arm64
Aug 13, 2026
Merged

bbondy merged 1 commit into
masterfrom
jest-no-sparkplug-macos-arm64

Conversation

@bbondy

@bbondy bbondy commented Aug 13, 2026 •

Copy link
Copy Markdown
Member

Summary

Jest workers die with SIGSEGV on macOS arm64 CI before any test body runs. Jest reports this as Test suite failed to run against 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 InternalFrame slot. A later GC conservative stack scan dereferences that slot and segfaults at address 0xe. --no-sparkplug removes 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-resolve pulls unrs-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-sparkplug is rejected 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 the flag because jest-worker forks with execArgv.

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:scripts also runs jest but only on c8a.4xlarge (Linux x86), so it's left alone.

Timing

Full suite, twice each way, same machine and commit:

run 1 run 2
before (Sparkplug on) 96.5s 69.8s
after (--no-sparkplug) 71.4s 70.4s

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-unit passes, same pass/fail counts as before
  • Verified workers actually inherit the flag — temporary probe asserting process.execArgv contains --no-sparkplug inside a worker passed, then removed
  • CI-style arg passthrough works: pnpm run test-unit -- --verbose --reporters=jest-junit --reporters=default <path>
  • test-unit:wallet still scopes correctly
  • Watch macOS arm64 builds — no new Test suite failed to run / SIGSEGV issues

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.
@bbondy
bbondy requested review from a team as code owners August 13, 2026 18:36
@bbondy
bbondy requested a review from petemill August 13, 2026 18:36
@github-actions github-actions Bot added CI/run-audit-deps Check for known npm/cargo vulnerabilities (audit_deps) CI/storybook-url Deploy storybook and provide a unique URL for each build labels Aug 13, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📋 Code Owners Summary

1 file(s) changed, 1 with assigned owners

2 team(s) affected: @brave/build-commands-reviewers, @brave/js-deps-reviewers


Owners and Their Files

@brave/js-deps-reviewers — 1 file(s)

@brave/build-commands-reviewers — 1 file(s)

@petemill petemill left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@brave-builds

Copy link
Copy Markdown
Collaborator

A Storybook has been deployed to preview UI for the latest push

@bbondy
bbondy merged commit f867e1e into master Aug 13, 2026
20 checks passed
@bbondy
bbondy deleted the jest-no-sparkplug-macos-arm64 branch August 13, 2026 23:18
@brave-builds brave-builds added this to the 1.95.x - Nightly milestone Aug 13, 2026
@brave-builds

Copy link
Copy Markdown
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI/run-audit-deps Check for known npm/cargo vulnerabilities (audit_deps) CI/storybook-url Deploy storybook and provide a unique URL for each build QA/No release-notes/exclude

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants