Skip to content

fix: prevent V8 turboshaft WASM Zone OOM during indexing (#298, #293)#322

Merged
colbymchenry merged 1 commit into
mainfrom
fix/wasm-zone-oom
May 22, 2026
Merged

fix: prevent V8 turboshaft WASM Zone OOM during indexing (#298, #293)#322
colbymchenry merged 1 commit into
mainfrom
fix/wasm-zone-oom

Conversation

@colbymchenry
Copy link
Copy Markdown
Owner

Summary

Fixes the Fatal process out of memory: Zone crash that aborts codegraph index / codegraph init partway through parsing large multi-language repos on Node 22 and 24 — including CodeGraph's own bundled Node 24 runtime. Resolves #298 and #293.

Root cause

Not a system OOM. V8's "turboshaft" optimizing WASM compiler exhausts its per-compilation Zone arena (a V8-internal arena, not the JS heap) while compiling tree-sitter's large WebAssembly grammars on a background thread — so it fires with tens of GB of RAM free. Stack: Zone::Expand → turboshaft::…WasmLoweringPhase → GenerateWasmCode → BackgroundCompileJob::Run.

Fix

Run node with V8's --liftoff-only, keeping grammar compilation on the Liftoff baseline so it never reaches the optimizing tier. Delivered two ways:

  • the bundled launcher (scripts/build-bundle.sh) and the Windows npm-shim pass the flag directly (zero overhead for installed users), and
  • a one-shot CLI re-exec guard covers every other launch path (from source, npx, a globally linked dev build).

The flag must be on node's command line — setFlagsFromString, worker execArgv, and NODE_OPTIONS all fail to apply it (verified). And empirically --no-wasm-tier-up / --no-wasm-dynamic-tiering do not prevent the crash; only --liftoff-only does.

Validation

Reproduced the exact issue stack with the real indexer on the shipped Node 24.16 runtime against a generated 2,880-file / 18-language repo, then confirmed the fix:

scenario (real codegraph index, Node 24.16) result
unfixed (control) 💥 Fatal process out of memory: Zone
--no-wasm-tier-up / --no-wasm-dynamic-tiering 💥 still crashes
--liftoff-only (the fix) ✅ 2,880 files, 19,200 nodes
fixed build, plain node (re-exec guard) ✅ 2,880 files, 19,200 nodes

A/B on the same fixed build toggling only the guard: CODEGRAPH_NO_RELAUNCH=1 → 💥 crash; normal → ✅. MCP server verified working through the re-exec. Full suite (737) + 7 new tests pass.

🤖 Generated with Claude Code

Large multi-language indexes crashed with `Fatal process out of memory:
Zone` on Node 22/24 (including the bundled runtime) — V8's turboshaft
optimizing WASM compiler exhausts its per-compilation Zone arena while
compiling tree-sitter grammars on a background thread, even with tens of
GB free (the Zone is a V8-internal arena, not the JS heap).

Run node with V8 `--liftoff-only`, which keeps grammar compilation on the
Liftoff baseline and never reaches the optimizing tier. Delivered via the
bundled launcher + a one-shot CLI re-exec guard for all other launch
paths. Empirically only `--liftoff-only` stops it (`--no-wasm-tier-up` /
`--no-wasm-dynamic-tiering` do not), and it must be on node's command
line (setFlagsFromString / worker execArgv / NODE_OPTIONS all fail).

Reproduced the exact crash with the real indexer on Node 24.16 against a
2,880-file / 18-language repo and confirmed the fix eliminates it; full
suite + 7 new tests pass. Bumps to 0.9.4.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@colbymchenry colbymchenry merged commit e5d6330 into main May 22, 2026
@colbymchenry colbymchenry deleted the fix/wasm-zone-oom branch May 22, 2026 10:39
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.

Fatal process out of memory (Zone) during parsing — V8 WASM compilation OOM on Node v24

1 participant