Windows: Node child-process pipe setup returns EPERM/PID 0; inherited streams succeed
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 125k
- Forks
- 19.4k
- PR merge metrics
- PR metrics pending
Description
Summary
In the Windows Codex desktop app, Node child-process calls fail with EPERM/PID 0 whenever any standard stream is piped. The same executable launches successfully with all standard streams inherited. Direct Git execution also succeeds.
This blocks a local verification workflow that must capture exact command output. The observations isolate the failure to the piped-launch path, but do not identify the failing native Windows call or establish the enforcing component.
Environment
- Windows 11 Home Single Language, 25H2, build 26200.9445, x64.
- Active client: OpenAI.Codex desktop MSIX package 26.901.6511.0.
- Running desktop backend: codex-cli 0.153.4.
- Separate CLI first on PATH:
0.145.0; an additional npm installation reports@openai/codex 0.144.5. These are not the backend running this desktop session; no causal relationship is established. - Bundled Node: v24.19.0, under
%USERPROFILE%\.cache\codex-runtimes\codex-primary-runtime\dependencies\node\bin\node.exe. - Git: 2.54.0.windows.1,
C:\Program Files\Git\cmd\git.exe. - Working directory: an existing local workspace; identifying path omitted.
- No Node execution flags,
NODE_OPTIONS, or enabled Node permission model.
Windows version details were obtained from registry/runtime metadata because CIM access was denied. The legacy registry product label says Windows 10; the reported 25H2/build 26200 identifies Windows 11.
Minimal reproduction
Run this JavaScript using the affected bundled Node executable, from the affected workspace. process.cwd() replaces the private workspace path. The trust setting below is command-scoped; no global Git configuration is changed.
const { spawnSync } = require("node:child_process");
const cwd = process.cwd();
const git = "C:/Program Files/Git/cmd/git.exe";
const args = [
"--no-optional-locks",
"-c", `safe.directory=${cwd}`,
"-C", cwd,
"--version"
];
for (const stdio of [
["inherit", "pipe", "inherit"],
["inherit", "inherit", "inherit"]
]) {
const r = spawnSync(git, args, {
cwd, stdio, encoding: "utf8", timeout: 10000
});
console.log({
stdio,
status: r.status,
pid: r.pid,
error: r.error?.code,
errno: r.error?.errno,
stdout: r.stdout
});
}
The readable version-string probe uses UTF-8 decoding. The blocked verification workflow separately requires raw-byte capture. The sanitized reproduction has not been rerun after substituting the private workspace path.
Previously observed comparisons
All comparisons used the same working directory and unchanged environment.
| Invocation | Result |
|---|---|
Direct Git --version |
Exit 0 |
| Node → Git, default pipes, bare executable name | EPERM, PID 0 |
| Same, absolute Git executable | EPERM, PID 0 |
| Node → Git, all streams inherited | Exit 0, version printed |
| Node → Git, only stdin piped | EPERM, PID 0 |
| Node → Git, only stdout piped | EPERM, PID 0 |
| Node → Git, only stderr piped | EPERM, PID 0 |
| Node → itself, default pipes / inherited streams | EPERM / exit 0 |
For the failed piped invocation: error EPERM, errno -4048, PID 0, status null.
The comparison matrix was not repeated during the version-only follow-up.
Expected behavior
A supported, permitted child-process invocation should capture stdout successfully and preserve exact stdout bytes, separate stderr diagnostics, exit status, and launch/timeout error detection, or provide a diagnostic identifying the relevant restriction and supported recovery path. Inherited output alone does not satisfy this workflow.
Diagnostics and limitations
- No matching events appeared in the inspected 30-minute window in AppLocker EXE/DLL, Code Integrity Operational, Defender Operational, or Security events 4656/4663/4688. This does not exclude an unlogged restriction.
- Version-only CLI queries additionally emitted access-denied warnings concerning temporary alias creation and stale temporary-directory cleanup. Their relationship to the pipe failure is unknown.
- No native failure trace has been collected. The underlying cause is not established as managed access enforcement, endpoint protection, or a Node/libuv–Windows interaction.
- No repository files, configuration, protections, ownership settings, or global Git trust settings were changed during this diagnostic follow-up. No tracing software was installed.
- Exact timestamps, account identifiers, project names/paths, repository identities, and full logs are intentionally omitted from this public report.
Please identify the failing native Windows call, affected object/pipe, native error, and any enforcing component. Please provide a supported correction preserving existing protections, or a documented permitted equivalent preserving output bytes, diagnostics, and exit/error status.
Related report
- #35070 reports Windows Node child-process
EPERMfailures. This report adds an isolated piped-versus-inherited standard-stream comparison on desktop backend 0.153.4. A shared root cause or exact duplicate is not asserted.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by rerunning the supplied JavaScript minimal reproduction with the bundled Node v24.19.0 and compare piped versus inherited stdio. No repository files or tests are named; completion requires identifying the failing native Windows call, affected pipe or object, native error, and a supported correction or documented permitted equivalent that preserves output, diagnostics, and status.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript, node.js
- Domain
- devtools, operating-systems
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100