Process substitution causes indefinite hang - orphaned grandchild processes not terminated

Resolved 💬 3 comments Opened Dec 10, 2025 by ghul0 Closed Dec 11, 2025

What version of Codex is running?

codex-cli 0.66.0

What subscription do you have?

PRO

Which model were you using?

gpt-5.1-codex-max

What platform is your computer?

Linux 6.8.0-87-generic x86_64 x86_64

What issue are you seeing?

When Codex executes shell commands containing bash process substitution
(e.g., exec > >(tee -a file.log) 2>&1 && command), grandchild processes
like tee remain orphaned after the main command completes successfully.

Symptoms:

  • Codex hangs indefinitely waiting for command completion
  • raw_output.jsonl shows: "exit_code": null, "status": "in_progress"
  • Orphaned processes visible in ps: tee, timeout, python in sleeping state (S)
  • The actual command completes successfully (tests pass), but Codex never receives EOF

Example from logs:
``json
{
"type": "item.started",
"item": {
"type": "command_execution",
"command": "exec > >(tee -a /tmp/test.log) 2>&1 && python -m pytest tests/ -q",
"exit_code": null,
"status": "in_progress"
}
}
``
Process state after hang:
| PID | PPID | S | ELAPSED | CMD |
|--------|--------|---|---------|------------------------------|
| 135079 | 134817 | S | 01:06 | timeout 10m python -m pytest ... |
| 135084 | 135079 | S | 01:06 | tee -a /tmp/pytest.log |
| 135085 | 135079 | S | 01:06 | python -m pytest ... |

What steps can reproduce the bug?

Minimal reproduction

  1. Run Codex with a command using process substitution:

``bash
codex exec --dangerously-bypass-approvals-and-sandbox \
"exec > >(tee -a /tmp/test.log) 2>&1 && echo 'test passed'"
``

  1. Wait ~5-10 seconds, then check for orphaned processes:

``bash
pgrep -af 'tee.*test.log'
``

  1. Observe that tee process remains running even though echo completed.

## Full reproduction script

```bash
#!/bin/bash
# Save as /tmp/codex_hang_repro.sh
set -euo pipefail

# Record PIDs before test
BEFORE=$(pgrep -f 'tee.*codex_test' 2>/dev/null || true)

# Run codex with process substitution
timeout 30s codex exec --dangerously-bypass-approvals-and-sandbox \
"exec > >(tee -a /tmp/codex_test.log) 2>&1 && echo test" &
CPID=$!

sleep 10

# Check for orphaned processes
AFTER=$(pgrep -f 'tee.*codex_test' 2>/dev/null || true)
if [[ -n "$AFTER" ]]; then
echo "BUG REPRODUCED: Orphaned tee process found"
ps -p $AFTER -o pid,ppid,state,etime,cmd
kill -9 $AFTER 2>/dev/null
exit 1
fi
echo "No hang detected"
```

## Environment

  • Shell: bash
  • Note: Direct command execution works fine (~0.1s)
  • Note: Issue only occurs when Codex spawns the shell

What is the expected behavior?

When the main command completes (e.g., echo or pytest), all child processes
including those created by process substitution (tee) should be terminated,
and Codex should receive the exit code and return control to the user.

Expected:

  • Command completes in <1 second
  • All child processes terminated
  • exit_code: 0 reported
  • No orphaned processes

Additional information

_No response_

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗