Skip to content

node:child_process: validate command, file, and args inputs #3079

Description

@andrewtdiz

Summary

node:child_process setup should reject invalid command/file and args inputs before attempting to run a process. Perry currently treats missing commands as empty output or null results, and treats non-array args values as an empty args list, diverging from Node's ERR_INVALID_ARG_TYPE behavior.

Expected Node behavior

Local Node v25.9.0 probe:

const cp = require("node:child_process");
for (const [label, fn] of [
  ["exec missing", () => cp.exec()],
  ["exec number", () => cp.exec(123)],
  ["execSync missing", () => cp.execSync()],
  ["execSync number", () => cp.execSync(123)],
  ["execFile missing", () => cp.execFile()],
  ["execFile number file", () => cp.execFile(123)],
  ["execFile args string", () => cp.execFile("sh", "-c")],
  ["execFileSync missing", () => cp.execFileSync()],
  ["execFileSync args string", () => cp.execFileSync("sh", "-c")],
  ["spawnSync missing", () => cp.spawnSync()],
  ["spawnSync number", () => cp.spawnSync(123)],
  ["spawnSync args string", () => cp.spawnSync("sh", "-c")],
]) {
  try { fn(); console.log(label, "OK"); }
  catch (e) { console.log(label, e.name, e.code); }
}

Node throws TypeError ERR_INVALID_ARG_TYPE for missing/non-string command / file inputs and for non-object/non-array args values such as a string.

Current Perry evidence

  • crates/perry-runtime/src/child_process/mod.rs::js_child_process_exec() returns empty stdout (and optionally invokes the callback with no error) when cmd_ptr is null.
  • js_child_process_exec_sync() returns an empty Buffer/string when cmd_ptr is null.
  • js_child_process_spawn_sync() returns a null pointer when cmd_ptr is null instead of throwing.
  • js_child_process_exec_file() and js_child_process_exec_file_sync() call cp_read_string_header(file_ptr), and cp_read_string_header() maps 0 to an empty string.
  • cp_args_from_value() and cp_read_arg_strings() silently turn missing/non-array args into an empty vector and skip non-string entries, so execFileSync("sh", "-c") / spawnSync("sh", "-c") do not get Node's setup-time args validation.

Suggested test surface

  • Add child_process parity tests for missing/non-string command/file values across exec, execSync, execFile, execFileSync, and spawnSync.
  • Add non-array args tests for execFile, execFileSync, and spawnSync, especially string args.
  • Assert synchronous TypeError with ERR_INVALID_ARG_TYPE before any child process is launched.

Scope / non-goals

Duplicate search

  • child_process command args validation ERR_INVALID_ARG_TYPE
  • child_process spawnSync execFileSync execSync validation options
  • PR search: child_process command args validation ERR_INVALID_ARG_TYPE

Search found #2555 for broader option semantics but no issue covering command/file/args input validation.

Activity

  1. andrewtdiz commented on Jun 2, 2026

    @andrewtdiz
    ContributorAuthor

    I’m taking this together with the deterministic setup-options slice of #2555 as a focused node:child_process setup parity cut.\n\nIntended PR scope: validate command/file and args inputs across exec/execSync/execFile/execFileSync/spawnSync, reject invalid setup before launch with Node-shaped ERR_INVALID_ARG_TYPE errors, and add deterministic option coverage for sync input/maxBuffer/timeout behavior where it shares the same child_process setup path. Non-goals: stdio array/live spawn plumbing, AbortSignal/killSignal lifecycle semantics, uid/gid/detached/platform flags, and the lifecycle/IPC surface already handled by #4110.

  2. andrewtdiz commented on Jun 3, 2026

    @andrewtdiz
    ContributorAuthor

    Opened draft PR #4180 for this PR cut: #4180

    This adds parity coverage for the setup-time command/file/args validation surface and keeps it batched with the related sync buffered child_process option work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions