Version
v26.5.0 (also reproduced on Node 22, 24, 25)
Platform
The primary Docker reproduction ran on this host:
Linux dragon-pro18 6.18.35-1-cachyos-lts #1 SMP PREEMPT_DYNAMIC Sat, 13 Jun 2026 12:39:40 +0000 x86_64 GNU/Linux
Intel Core Ultra 9 285HX, 24 cores online
Docker replaces the userspace and Node installation but shares the host kernel and CPU. The same failure occurs with the host Node binary.
Subsystem
V8 / WebAssembly (observed through child_process)
What steps will reproduce the bug?
The minimal repository is:
https://github.com/gadicc/node-pglite-wasm-sigsegv-repro
It has one runtime dependency, @electric-sql/pglite@0.5.4. PGlite ships its PostgreSQL engine as WebAssembly; there is no native addon.
On a machine with at least 20 GiB available:
git clone https://github.com/gadicc/node-pglite-wasm-sigsegv-repro.git
cd node-pglite-wasm-sigsegv-repro
docker build -t pglite-node-sigsegv-repro .
docker run --rm pglite-node-sigsegv-repro
Equivalently, with a local Node installation:
Each of 16 child processes independently creates an in-memory PGlite client, runs SELECT 1, awaits client.close() in finally, and exits. The parent repeats that wave up to 50 times and stops on the first failure. There is no Vitest, Vite, test runner, application code, native addon, IPC dependency, or database persistence.
The memory warning matters: the observed cgroup peak was approximately 19 GiB. The recorded failing run had oom=0 and oom_kill=0.
How often does it reproduce? Is there a required condition?
It is intermittent and requires concurrent processes in the measured setup.
Two clean Node 26 official-image runs failed at waves 13 and 8. Other results
without V8 CLI overrides were:
| Node |
Result |
| 25 |
1/20 waves failed |
| 24 |
4/45 waves failed |
| 22 |
1/10 waves failed |
| 20 |
0/40 waves failed |
The Node 20 result is a non-reproduction in an intermittent test, not evidence that it is unaffected. Official Node 20, 22, 24, and 26 images expose the same relevant defaults: Liftoff, lazy compilation, dynamic tiering, and WASM tier-up are enabled, with up to 128 compilation tasks. Node 20 did reproduce with --no-liftoff, which forces the optimizing compiler.
The Node 27 V8 canary failed at wave 17 with child_process.fork() and failed 2/50 waves with ordinary child_process.spawn(). A sequential one-child control passed 50/50 waves.
What is the expected behavior? Why is that the expected behavior?
Every child should complete the query, close the PGlite client, and exit with code 0.
What do you see instead?
An intermittent child is terminated by SIGSEGV:
node=v26.5.0 v8=14.6.202.34-node.24 platform=linux arch=x64 children=16 waves=50
wave=1 passed=16/16
...
wave=8 passed=15/16
child=10 code=null signal=SIGSEGV elapsedMs=4315
failedWaves=1 completedWaves=8 requestedWaves=50
Additional information
Native diagnostics from a sanitized-environment reproduction:
strace recorded an initial SIGSEGV with SEGV_MAPERR at a large guarded WASM address.
- Node's
node::TrapWebAssemblyOrContinue called raise(SIGSEGV) after V8 declined to handle the address as a valid WASM trap.
- The retained core records the resulting
SI_TKILL signal.
- GDB placed another crash in the lazy WASM compilation path through
LiftoffAssembler::PrepareCall, ExecuteLiftoffCompilation, CompileLazy, and Runtime_WasmCompileLazy, with background Turboshaft compilation active. A separate retained crash was in v8::internal::MarkingBarrier::MarkValueLocal.
Relevant flag controls on Node 25:
- default: reproduced;
--wasm-enforce-bounds-checks: reproduced;
--wasm-num-compilation-tasks=1: reproduced;
--no-wasm-tier-up: passed 100/100 waves in that version;
--no-liftoff: reproduced.
The Node 27 canary nevertheless reproduced with both --no-wasm-tier-up and --liftoff-only, so no single WASM tier is universally required.
I also built the exact PGlite 0.5.4 tag using its official pnpm build:all:debug workflow. That PostgreSQL WASM used -g,
-gsource-map, and --no-wasm-opt; LLVM verified 1,322 DWARF compilation units without errors. With Node 25.2.1, a sequential control passed 5/5 waves and eight concurrent children passed 5/5 waves, while 16 concurrent children
reproduced SIGSEGV in wave 2. The cgroup peak was 67,306,729,472 bytes (62.7 GiB), with oom=0 and oom_kill=0.
Runtime controls using the same PGlite version and concurrency:
- Bun 1.3.11 / JavaScriptCore: 50/50 waves passed;
- Deno 2.8.0 / V8 14.9.207.2, default: 50/50 passed;
- Deno 2.8.0 / V8 14.9.207.2,
--no-liftoff: 50/50 passed.
The evidence therefore establishes a Node-runtime-specific interaction in the tested configurations, but does not yet distinguish Node's WASM trap/embedding layer or build configuration from a V8 defect exposed by Node. d8 is V8's standalone JavaScript shell; reproducing there without Node or its APIs would prove that the bug exists independently in V8. I would appreciate guidance on whether this should be routed or cross-filed to V8.
On 2026-07-14 I searched open Node and V8 reports for PGlite, TrapWebAssemblyOrContinue, WasmCompileLazy, LiftoffAssembler, and concurrent WASM SIGSEGVs, and found no exact duplicate. The reproduction README records the related but materially different reports.
Lastly,
- Co-authored with Codex gpt-5.6-sol, reasoning: high, with significant human input.
- This issue was opened by me personally by hand and without any automation.
Edit 1: Added PGLite debug build info in "Additional Information" above.
Version
v26.5.0 (also reproduced on Node 22, 24, 25)
Platform
Subsystem
V8 / WebAssembly (observed through
child_process)What steps will reproduce the bug?
The minimal repository is:
https://github.com/gadicc/node-pglite-wasm-sigsegv-repro
It has one runtime dependency,
@electric-sql/pglite@0.5.4. PGlite ships its PostgreSQL engine as WebAssembly; there is no native addon.On a machine with at least 20 GiB available:
Equivalently, with a local Node installation:
Each of 16 child processes independently creates an in-memory PGlite client, runs
SELECT 1, awaitsclient.close()infinally, and exits. The parent repeats that wave up to 50 times and stops on the first failure. There is no Vitest, Vite, test runner, application code, native addon, IPC dependency, or database persistence.The memory warning matters: the observed cgroup peak was approximately 19 GiB. The recorded failing run had
oom=0andoom_kill=0.How often does it reproduce? Is there a required condition?
It is intermittent and requires concurrent processes in the measured setup.
Two clean Node 26 official-image runs failed at waves 13 and 8. Other results
without V8 CLI overrides were:
The Node 20 result is a non-reproduction in an intermittent test, not evidence that it is unaffected. Official Node 20, 22, 24, and 26 images expose the same relevant defaults: Liftoff, lazy compilation, dynamic tiering, and WASM tier-up are enabled, with up to 128 compilation tasks. Node 20 did reproduce with
--no-liftoff, which forces the optimizing compiler.The Node 27 V8 canary failed at wave 17 with
child_process.fork()and failed 2/50 waves with ordinarychild_process.spawn(). A sequential one-child control passed 50/50 waves.What is the expected behavior? Why is that the expected behavior?
Every child should complete the query, close the PGlite client, and exit with code 0.
What do you see instead?
An intermittent child is terminated by
SIGSEGV:Additional information
Native diagnostics from a sanitized-environment reproduction:
stracerecorded an initialSIGSEGVwithSEGV_MAPERRat a large guarded WASM address.node::TrapWebAssemblyOrContinuecalledraise(SIGSEGV)after V8 declined to handle the address as a valid WASM trap.SI_TKILLsignal.LiftoffAssembler::PrepareCall,ExecuteLiftoffCompilation,CompileLazy, andRuntime_WasmCompileLazy, with background Turboshaft compilation active. A separate retained crash was inv8::internal::MarkingBarrier::MarkValueLocal.Relevant flag controls on Node 25:
--wasm-enforce-bounds-checks: reproduced;--wasm-num-compilation-tasks=1: reproduced;--no-wasm-tier-up: passed 100/100 waves in that version;--no-liftoff: reproduced.The Node 27 canary nevertheless reproduced with both
--no-wasm-tier-upand--liftoff-only, so no single WASM tier is universally required.I also built the exact PGlite 0.5.4 tag using its official
pnpm build:all:debugworkflow. That PostgreSQL WASM used-g,-gsource-map, and--no-wasm-opt; LLVM verified 1,322 DWARF compilation units without errors. With Node 25.2.1, a sequential control passed 5/5 waves and eight concurrent children passed 5/5 waves, while 16 concurrent childrenreproduced
SIGSEGVin wave 2. The cgroup peak was 67,306,729,472 bytes (62.7 GiB), withoom=0andoom_kill=0.Runtime controls using the same PGlite version and concurrency:
--no-liftoff: 50/50 passed.The evidence therefore establishes a Node-runtime-specific interaction in the tested configurations, but does not yet distinguish Node's WASM trap/embedding layer or build configuration from a V8 defect exposed by Node.
d8is V8's standalone JavaScript shell; reproducing there without Node or its APIs would prove that the bug exists independently in V8. I would appreciate guidance on whether this should be routed or cross-filed to V8.On 2026-07-14 I searched open Node and V8 reports for PGlite,
TrapWebAssemblyOrContinue,WasmCompileLazy,LiftoffAssembler, and concurrent WASMSIGSEGVs, and found no exact duplicate. The reproduction README records the related but materially different reports.Lastly,
Edit 1: Added PGLite debug build info in "Additional Information" above.