You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
node:child_process largely stubbed — 52 radar tests fail with 'value is not a function' #1780
node:child_process is largely stubbed — 52 of ~74 judged tests fail at runtime with value is not a function (Perry resolves a child_process method to a non-callable stub, then the test calls it).
Audit the child_process surface (spawn/exec/execFile/fork/spawnSync/...) — the 52 failures indicate most entry points return stubs rather than working implementations. File sub-tickets per method family once the surface is mapped, or implement the core spawn/exec path first (most tests bottom out there).
Note: some child_process tests are also in the feature-link-artifact bucket (#1778) — confirm linkage before attributing a failure to a missing impl.
Context: full #800 radar sweep (1300 judged), perry 0.5.1028.
Fixed:child_process.exec(cmd[, options], callback) — js_child_process_exec was a null stub and the codegen lowered the callback then discarded it, so exec(cmd, cb) never fired its callback. exec now runs the command (shell, like execSync) and invokes the callback with (err, stdout, stderr) (immediate-callback model, same as the async fs wrappers). The callback is located whether it sits in the options slot (exec(cmd, cb)) or the third slot (exec(cmd, options, cb)); non-zero exit yields an Error; the no-callback form still returns the stdout string. execSync / spawnSync already worked.
Still open — the larger part of this ticket: the dominant node-core child_process pattern is the streaming API:
constchild=spawn(cmd,args);child.stdout.on('data',d=>…);// child.stdout is currently a string → "(string).on is not a function"child.on('exit'|'close'|'error',…);
js_child_process_spawn / exec (the streaming forms) are explicit null-returning stubs ("needs event loop integration"). A real ChildProcess object — stdout/stderr as Readable streams, stdin Writable, EventEmitter (spawn/exit/close/error/message), pid/kill(), and IPC for fork — is a sizeable feature requiring subprocess + event-loop integration. Most of the 52 radar fails bottom out there. Suggest splitting that into its own ticket (spawn-with-streams) and keeping this for the audit.
Knocked out the remaining easy stubs in PR #1926 (runtime-only):
Options were ignored — spawn/exec/execFile/execFileSync/spawnSync/execSync now honor { cwd, env, shell } (the options pointer was already threaded to js_child_process_spawn_streams, just never read). env replaces the environment wholesale per Node semantics; shell:true/shell:"<path>" joins command+args into a <shell> -c line.
Listener removal was a no-op — removeListener/off now rebuild the listener array without the matching closure; removeAllListeners([event]) clears one event or all.
New test_issue_1780_options.ts is byte-identical to node --experimental-strip-types. The follow-ups #1856 (ChildProcess/Stream exports) and #1857 (promisify exec/execFile) closed via #1861.
Still open (the large remaining piece):fork + IPC (send/disconnect/'message', channel/connected semantics). Perry has no async subprocess reactor, so a real fork needs subprocess + event-loop integration — worth its own ticket rather than folding into this one. Leaving #1780 open to track that.
The original failure cluster here — 52 radar tests failing with value is not a function because spawn()'s .stdout was a string — is fixed: streaming spawn() (#1858), exec callback (#1828), execFile/execFileSync (#1858), ChildProcess/Stream exports + promisify(exec/execFile) (#1861, closing #1856/#1857), and cwd/env/shell options + listener removal (#1926). test_parity_child_process is byte-identical to Node and out of known_failures.json.
The remaining surface is split into granular tickets (per the "no umbrella issues" preference) and this umbrella is closed:
Activity
proggeramlug commentedon May 26, 2026
Partial fix in #1827 (PR), plus scope mapping:
Fixed:
child_process.exec(cmd[, options], callback)—js_child_process_execwas anullstub and the codegen lowered the callback then discarded it, soexec(cmd, cb)never fired its callback. exec now runs the command (shell, likeexecSync) and invokes the callback with(err, stdout, stderr)(immediate-callback model, same as the async fs wrappers). The callback is located whether it sits in the options slot (exec(cmd, cb)) or the third slot (exec(cmd, options, cb)); non-zero exit yields anError; the no-callback form still returns the stdout string.execSync/spawnSyncalready worked.Still open — the larger part of this ticket: the dominant node-core child_process pattern is the streaming API:
js_child_process_spawn/exec(the streaming forms) are explicitnull-returning stubs ("needs event loop integration"). A realChildProcessobject —stdout/stderras Readable streams,stdinWritable, EventEmitter (spawn/exit/close/error/message),pid/kill(), and IPC forfork— is a sizeable feature requiring subprocess + event-loop integration. Most of the 52 radar fails bottom out there. Suggest splitting that into its own ticket (spawn-with-streams) and keeping this for the audit.fix(hir,runtime): builtin-prototype .call/.apply (#1777), fs.readdir …
fix(hir,runtime): builtin-prototype .call/.apply (#1777), fs.readdir …
feat(child_process): streaming spawn() ChildProcess + execFile/execFi…
feat(child_process,util): ChildProcess/Stream exports (#1856) + promi…
proggeramlug commentedon May 27, 2026
Knocked out the remaining easy stubs in PR #1926 (runtime-only):
spawn/exec/execFile/execFileSync/spawnSync/execSyncnow honor{ cwd, env, shell }(the options pointer was already threaded tojs_child_process_spawn_streams, just never read).envreplaces the environment wholesale per Node semantics;shell:true/shell:"<path>"joins command+args into a<shell> -cline.removeListener/offnow rebuild the listener array without the matching closure;removeAllListeners([event])clears one event or all.New
test_issue_1780_options.tsis byte-identical tonode --experimental-strip-types. The follow-ups #1856 (ChildProcess/Stream exports) and #1857 (promisify exec/execFile) closed via #1861.Still open (the large remaining piece):
fork+ IPC (send/disconnect/'message',channel/connectedsemantics). Perry has no async subprocess reactor, so a realforkneeds subprocess + event-loop integration — worth its own ticket rather than folding into this one. Leaving #1780 open to track that.feat(child_process): honor cwd/env/shell options + real listener remo…
proggeramlug commentedon May 27, 2026
The original failure cluster here — 52 radar tests failing with
value is not a functionbecausespawn()'s.stdoutwas a string — is fixed: streamingspawn()(#1858),execcallback (#1828),execFile/execFileSync(#1858),ChildProcess/Streamexports +promisify(exec/execFile)(#1861, closing #1856/#1857), andcwd/env/shelloptions + listener removal (#1926).test_parity_child_processis byte-identical to Node and out ofknown_failures.json.The remaining surface is split into granular tickets (per the "no umbrella issues" preference) and this umbrella is closed:
fork()+ IPC (send/disconnect/'message'/channel)stdin.write(),kill()on a running child)Errormissing.code/.signal/.killed/.cmdspawnSyncresult missingpid/signal/output/errorencodingoption (no Buffer stdout/stderr)execSync/execFileSyncdon't throw on non-zero exitClosing in favor of those.
feat(node:child_process): async spawn reactor, fork()+IPC, exec error…
feat(node:child_process): async spawn reactor, fork()+IPC, exec error…