openai / openai/codex

[unified_exec] Interrupting a turn leaves the in-flight shell process running

Open
#42,717 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

app bug tool-calls
Dominant language
Rust
Stars
125k
Forks
19.4k
PR merge metrics
PR metrics pending

Description

What version of the Codex App are you using (From “About Codex” dialog)?

26.901.31953

What subscription do you have?

Pro

What platform is your computer?

Darwin 25.5.0 arm64 arm

What issue are you seeing?

When I interrupt an active turn while exec_command or write_stdin is waiting on a long-running command, Codex reports the turn as interrupted, but the shell process continues running in the background.

For example, after starting "sleep 600" and pressing Stop, the turn ends but the sleep process remains alive.

This is misleading because Stop appears to stop the active operation. The remaining process may continue consuming resources, writing files, holding ports or locks, and interfering with later commands.

The issue is limited to interactive Unified Exec commands that can return a process_id. One-shot execution already terminates its process on cancellation.

What steps can reproduce the bug?
  1. Start Codex with Unified Exec enabled.

  2. Ask Codex:

    Use exec_command to run:
    sh -c 'echo $$ > /tmp/codex-turn-abort-repro.pid; exec sleep 600'

    Set yield_time_ms=30000. If a process_id is returned, keep polling it
    with write_stdin and wait 30000ms each time.

  3. While exec_command or write_stdin is waiting, press Stop.

  4. In another terminal, run:

    pid="$(cat /tmp/codex-turn-abort-repro.pid)"
    kill -0 "$pid" && echo "process is still running"

  5. Observe that the process is still running.

Cleanup:

kill "$(cat /tmp/codex-turn-abort-repro.pid)"
rm /tmp/codex-turn-abort-repro.pid

What is the expected behavior?

Interrupting a turn should terminate shell processes started by that turn and remove them from the background process store.

If process persistence is intentional, Codex should distinguish Detach from Stop and clearly tell the user that the process is still running.

Additional information

Root-cause analysis
The process is stored in the session-level ProcessStore before the initial yield wait. The source comment explicitly states that this is done so interrupting the turn does not terminate the background process:

  1. handle_task_abort cancels the turn token and aborts the task, but it does not terminate Unified Exec processes:
  2. The tool dispatcher aborts the tool handler future:
  3. Aborting the future does not drop the process because ProcessStore still owns an Arc.
  4. ProcessEntry contains no turn identifier, so the process manager cannot determine which processes belong to the aborted turn:
  5. Process termination currently happens only through explicit terminal termination or session-wide cleanup:
    • process_manager.rs lines 1673–1720
      The one-shot execution path already handles cancellation by calling terminate_confirmed(), which demonstrates the expected cancellation behavior:
  • oneshot.rs lines 25–74
    Possible implementation direction
  • Record the owning turn ID in each ProcessEntry.
  • When a turn is aborted, terminate and remove all processes owned by that turn.
  • Cover both local and ExecServer-backed processes.
  • Add regression tests for interruption:
    • during the initial exec_command yield;
    • during a write_stdin poll;
    • with and without the local sandbox;
    • without affecting normally completed turns or explicitly detached processes.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with codex-rs/core/src/unified_exec/process_manager.rs and unified_exec/mod.rs, then trace the abort flow in tasks/mod.rs and tools/parallel.rs. Compare the cancellation behavior in unified_exec/oneshot.rs and run the existing Unified Exec tests before adding regression coverage for initial waits, write_stdin polling, sandbox modes, and detached processes. Done means aborted-turn processes terminate and leave the process store without changing normal completion or explicit detachment.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
cli, operating-systems
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.