Summary
pnpm dev cannot start the stack on Windows. It fails immediately with Error: spawn EINVAL before Postgres, the API, the gateway or the web app come up.
Environment
- Windows 10 (10.0.26200), PowerShell
- Node v22.23.2
- pnpm 11.20.0
facility at ae68401
Reproduction
Actual
Error: spawn EINVAL
at ChildProcess.spawn (node:internal/child_process:420:11)
at spawn (node:child_process:787:9)
errno: -4071,
code: 'EINVAL',
syscall: 'spawn'
Expected
The development stack starts, as it does on macOS and Linux.
Root cause
scripts/dev.mjs resolves the package manager to a batch file on Windows:
const pnpm = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
but run() spawns it without a shell:
const child = spawn(command, args, { cwd, env: environment, stdio: "inherit" });
Since Node 18.20 / 20.12 (the fix for CVE-2024-27980), child_process.spawn refuses to launch a .cmd or .bat file unless shell is set, and raises EINVAL.
Every pnpm invocation in the script is affected: pnpm install, the shared-package build, @facility/db migrate, @facility/db seed, and pnpm run dev:services. The first one aborts the run.
A secondary effect: spawn throws synchronously here, so the child.once("error", ...) handler in run() never runs and the friendly Could not start <label> hint is replaced by a raw stack trace, which makes the failure harder to diagnose than it needs to be.
Minimal confirmation on the same machine:
pnpm.cmd no-shell (current) : SYNC THROW code=EINVAL
pnpm.cmd shell:true : exited code=0
docker no-shell : exited code=0
docker is unaffected because it is a real executable, so the fix should be narrow rather than applying a shell to every spawn.
Suggested fix
Set shell only for .cmd and .bat commands on win32, leaving real executables and POSIX platforms with their current argument handling.
Happy to open a PR for this.
Summary
pnpm devcannot start the stack on Windows. It fails immediately withError: spawn EINVALbefore Postgres, the API, the gateway or the web app come up.Environment
facilityatae68401Reproduction
Actual
Expected
The development stack starts, as it does on macOS and Linux.
Root cause
scripts/dev.mjsresolves the package manager to a batch file on Windows:but
run()spawns it without a shell:Since Node 18.20 / 20.12 (the fix for CVE-2024-27980),
child_process.spawnrefuses to launch a.cmdor.batfile unlessshellis set, and raisesEINVAL.Every
pnpminvocation in the script is affected:pnpm install, the shared-package build,@facility/db migrate,@facility/db seed, andpnpm run dev:services. The first one aborts the run.A secondary effect:
spawnthrows synchronously here, so thechild.once("error", ...)handler inrun()never runs and the friendlyCould not start <label>hint is replaced by a raw stack trace, which makes the failure harder to diagnose than it needs to be.Minimal confirmation on the same machine:
dockeris unaffected because it is a real executable, so the fix should be narrow rather than applying a shell to every spawn.Suggested fix
Set
shellonly for.cmdand.batcommands onwin32, leaving real executables and POSIX platforms with their current argument handling.Happy to open a PR for this.