Nested exec can orphan a mutating child while outer wait reports complete
Summary
A long-running tools.exec_command invoked inside functions.exec can yield with its own session still running. If the wrapper only emits result.output, the nested session_id is discarded. Waiting on the outer functions.exec cell can then report completion even though the child shell process is still mutating the filesystem.
Observed impact
This happened during a large git switch. The outer cell completed with no output while the Git process continued in the background holding index.lock. A later status check raced the checkout. When the orphaned Git process was stopped, HEAD and the index were unchanged, but the working tree had been only partially transitioned: thousands of tracked deletions/modifications plus hundreds of untracked files. Recovery was possible only because HEAD/index remained intact and the filesystem state was separately preserved.
Reproduction shape
- Call
functions.exec. - Inside it, await
tools.exec_commandfor a command that runs beyond the nested yield window. - Emit only
result.output, omittingresult.session_id. - The outer call yields a cell ID; wait on that cell.
- Observe the outer cell complete while the nested child process remains alive.
Expected safety behavior
One of the following should hold:
functions.execautomatically retains and surfaces nested exec session IDs;- the outer cell remains alive until every awaited nested exec finishes;
- nested long-running exec calls are rejected unless their session handle is explicitly consumed; or
- child processes are terminated when the outer isolate completes.
For mutating commands, an outer completed result must not coexist with an unreported live child process. A regression test using a slow filesystem mutation would be valuable.
1 Comment
Potential duplicates detected. Please review them and close your issue if it is a duplicate.
Powered by Codex Action