Commands hang indefinitely when timeout occurs on shell-wrapped processes
What version of Codex is running?
codex-cli 0.42.0
Which model were you using?
gpt-5-codex
What platform is your computer?
Linux 6.6.87.2-microsoft-standard-WSL2 x86_64 unknown
What steps can reproduce the bug?
When a shell tool call times out, Codex only kills the shell wrapper (bash -lc), not its child processes. These orphaned children keep stdout/stderr pipes open, even causing Codex to hang indefinitely in some cases despite the 366s wrapper timeout.
Steps to Reproduce
On any Linux machine:
- Launch Codex (CLI or desktop).
- Run (with a 5-second timeout):
mkfifo pipe.$$; (while true; do echo child; sleep 1; done) > pipe.$$ & cat pipe.$$ - Wait for the five-second timeout. Codex logs that the tool call timed out, but the UI remains on "working".
- In another terminal, run
ps -ef | grep '[p]ipe'(or inspect the loop). Both the background writer andcatare still running.
Observed Behavior
Even after the timeout, the child pipeline keeps running. Because those descendants keep the stdout pipe open, Codex's reader tasks never finish, so the turn remains stuck until you manually interrupt.
Expected Behavior
When a tool call times out, Codex should terminate the entire process tree so stdout and stderr close, the readers exit, and the tool call finishes cleanly.
Additional Notes
A real-world example is cargo test --release with a timeout. Cargo's child runners survive the timeout, continue emitting output, and Codex stays in "working" until you abort the turn.
Root Cause
- Commands wrapped in
bash -lccreate a shell wrapper process. - On timeout, only the wrapper is killed via its PID.
- Child processes become orphaned but keep running.
- They hold stdout/stderr pipes open indefinitely.
- Reader tasks block waiting for EOF that never arrives.
Fix
- Use
setsid()to create process groups. - Kill the entire process group with
kill(-pid, signal). - Ensures all descendants terminate and pipes close properly.
11 Comments
<img width="2403" height="561" alt="Image" src="https://github.com/user-attachments/assets/f2fdd559-55b1-4149-9a36-c8ebb771e03b" />
Associated codex-tui.log line:
2025-09-27T05:28:22.762846Z INFO FunctionCall: shell({"command":["bash","-lc","/usr/bin/python3 - <<'PY'\nimport
signal, time\nsignal.signal(signal.SIGHUP, signal.SIG_IGN)\nwhile True:\n print('child', flush=True)\n
time.sleep(1)\nPY"],"timeout_ms":2000,"workdir":"/root"}
The same thing happens on Linux, and I can't figure out why. I also looked at the code but found nothing. Not all commands hang and ignore the timeout, but the simplest one that does this is
timeout 30 cargo test. If there is a deadlock in the code, the codex will hang despite the timeout. Always.I have a fix in place already for windows, linux and macOS. I just haven't pushed the branch.
Agree with OP that any command launched should be handled as a process group. The agent should probably be taught about job management the way codex cloud seems to be (just my speculation but I see codex cloud seemingly make decisions about whether to wait longer or not for commands it launched).
For me codex waited over 10 hours on a process which, ironically, was an experiment with go process cancellation. I don't know if it was supposed to have a built in timeout but if it did, it was either never triggered or the action the timeout handler took was ineffective. From the session log (shortened to remove some irrelevant detail):
As you can see, I left it running over night and it never resolved. This was on codex-cli 0.41.0. Here's the actual command which may be useful for reproduction purposes:
I have the same issue on various processes. MacOS. Claude Code has a default 2min timeout which is applied to all processes, which can be problematic sometimes but is significantly better then getting stuck indefinitely.
Would appreciate a quick fix soon & a good fix later.
Affecting several folks on our end as well. In our case the stuck script is:
This matches @danielchristiancazares thesis about pipes.
@jif-oai @bolinfest I've a fix solidified, but banging my head against a wall on how to properly unit test this without causing the same blocking behavior when/if regressions occur. Shall I open a draft PR for comments?
https://github.com/openai/codex/pull/6575 addresses this issue.
Thank you @etraut-openai !!
Not sure if related, but I've found that sometimes commands can hang for hours without response on OsX"run pwd" to hang, and "run pwd with timeout_ms to 1,000 ms" to hang, but "run pwd without bash -lc" to return immediately. I can see the difference in the tui logs.
Intentionally adding this to a closed issue since I'm not sure it merits a new one and might help someone searching.
codex-cli 0.58.0 OSX, iTerm and TMux
@bf4 i can confirm they remediated this particular root cause. they do some nasty python jiggery pokery to spawn detached grandchildren but it works. im not too sure what your issue is. i'd recommend opening a new ticket if you can reproduce it.