Version
v26.0.0 (official linux-x64 build from nodejs.org — primary repro)
also: v22.23.2 (x64), v24.20.0 / v26.0.0 (unofficial-builds riscv64)
Platform
Linux Acidmoon-PC 6.6.127-amd64-desktop-hwe #25.01.00.17 SMP PREEMPT_DYNAMIC x86_64 GNU/Linux (deepin; primary repro with the official node-v26.0.0-linux-x64 build)
Subsystem
child process
What steps will reproduce the bug?
// child.js
console.log("child execArgv =", JSON.stringify(process.execArgv));
console.log("child typeof WebAssembly =", typeof WebAssembly);
// repro.js — run: node repro.js (same directory)
const { spawn, fork } = require("child_process");
console.log("— spawn() with execArgv option:");
spawn(process.execPath, ["child.js"], {
stdio: "inherit",
execArgv: ["--jitless"], // should make WebAssembly unavailable in child
});
// fork() for comparison, after the spawn child exits:
setTimeout(() => {
console.log("— fork() with execArgv option:");
fork("child.js", [], { stdio: "inherit", execArgv: ["--jitless"] });
}, 1500);
Expected per docs (child_process.spawn() options.execArgv: “List of string arguments passed to the executable. Default: process.execArgv.”):
— spawn() with execArgv option:
child execArgv = ["--jitless"]
child typeof WebAssembly = undefined
— fork() with execArgv option:
child execArgv = ["--jitless"]
child typeof WebAssembly = undefined
How often does it reproduce? Is there a required condition?
100% of runs, on all Node builds tested (v22.23.2 x64, official v26.0.0 x64, unofficial-builds v24.20.0 & v26.0.0 riscv64). The spawn() form ignores the option when process.execPath is the command; fork() honored it on v26 (x64 and riscv64).
What is the expected behavior? Why is that the expected behavior?
Expected: the execArgv array is passed to the spawned Node executable — that is exactly what the current docs state for spawn(). The --jitless case makes this behavior-provable rather than introspection-only: a child started with --jitless must have typeof WebAssembly === "undefined" (verified by running node --jitless child.js directly).
What do you see instead?
— spawn() with execArgv option:
child execArgv = []
child typeof WebAssembly = object # flag had NO effect
— fork() with execArgv option:
child execArgv = ["--jitless"]
child typeof WebAssembly = undefined # fork works
Additional information
How we ran into this: while developing a workaround for a riscv64 V8 wasm SIGILL (separate issue, link to be added), an app-side fix that injected --no-wasm-lazy-compilation via spawn()'s execArgv did not take effect on the child (child still crashed at the same faulting page offset). Cross-checking on the official linux-x64 v26.0.0 with --jitless shows the option is silently dropped there too — so it is not architecture- or build-specific: either spawn()'s documented behavior regressed at some point (long-standing? v22 also affected), or the docs are wrong and execArgv is fork-only. Either way docs and implementation disagree today, and the current wording gives no hint that the option is ignored for spawn().
Workaround in the wild will inevitably be “put the flags in the args array manually” (which works, including node <flags> script.js ordering). Happy to test candidate fixes or bisect to the introducing commit if maintainers want.
— Acidmoon, KUBUDS Tech
Version
v26.0.0 (official linux-x64 build from nodejs.org — primary repro)
also: v22.23.2 (x64), v24.20.0 / v26.0.0 (unofficial-builds riscv64)
Platform
Subsystem
child process
What steps will reproduce the bug?
Expected per docs (
child_process.spawn()options.execArgv: “List of string arguments passed to the executable. Default:process.execArgv.”):How often does it reproduce? Is there a required condition?
100% of runs, on all Node builds tested (v22.23.2 x64, official v26.0.0 x64, unofficial-builds v24.20.0 & v26.0.0 riscv64). The
spawn()form ignores the option whenprocess.execPathis the command;fork()honored it on v26 (x64 and riscv64).What is the expected behavior? Why is that the expected behavior?
Expected: the
execArgvarray is passed to the spawned Node executable — that is exactly what the current docs state forspawn(). The--jitlesscase makes this behavior-provable rather than introspection-only: a child started with--jitlessmust havetypeof WebAssembly === "undefined"(verified by runningnode --jitless child.jsdirectly).What do you see instead?
Additional information
How we ran into this: while developing a workaround for a riscv64 V8 wasm SIGILL (separate issue, link to be added), an app-side fix that injected
--no-wasm-lazy-compilationviaspawn()'sexecArgvdid not take effect on the child (child still crashed at the same faulting page offset). Cross-checking on the official linux-x64 v26.0.0 with--jitlessshows the option is silently dropped there too — so it is not architecture- or build-specific: eitherspawn()'s documented behavior regressed at some point (long-standing? v22 also affected), or the docs are wrong andexecArgvis fork-only. Either way docs and implementation disagree today, and the current wording gives no hint that the option is ignored forspawn().Workaround in the wild will inevitably be “put the flags in the args array manually” (which works, including
node <flags> script.jsordering). Happy to test candidate fixes or bisect to the introducing commit if maintainers want.— Acidmoon, KUBUDS Tech