Repository navigation
Shell tool stays status=running after a fast-exiting command with no surviving descendant (1.18.30, server mode) #50424
Description
Description
A shell tool call stays status=running forever after a fast-exiting command that leaves no descendant at all. This is the variant #29294 described as a pipe FD leak in spawn; that issue was closed by the stale bot ("if the issue is still relevant please open a new one"), and the currently open reports (#47350, #49169, #50316) all cover the descendant holds the stdio pipes case, which is a different shape. #20902 closed as completed covers the background-child case.
What makes this instance worth filing: the usual explanations are excluded by construction rather than by argument.
Environment
- opencode
1.18.30, linux x64 opencode serve, driven over the HTTP API — no TUI- Running in a container; a real init is PID 1 (Kubernetes
shareProcessNamespace, so the kubelet'spausereaps orphans)
What happens
The session's own view of the wedged turn:
assistant message | completed: null
part tool | status: running | time.start set, time.end absent
Per-tool-call timings from GET /session/{id}/message, same session, immediately before the hang:
21:41:34 -> 21:41:37 mise run fmt (3s, fine)
21:41:41 -> 21:42:30 mise run test (49s, fine)
21:42:36 -> never cd /repo && cp internal/.../executor.go /tmp/executor.go.bak && sed -i 's/.../.../' ...
The hung command is cp followed by sed -i. Nothing backgrounds, nothing is long-lived, every process exits in milliseconds. It stayed running for over 20 minutes, until our own step timeout tore the container down.
Ruled out, inside the container, while it was wedged
- No surviving descendant.
psshowed only theopencodeprocess itself. Nothing from the command was alive — so no process was holding the stdio pipes, which is what separates this from Shell tool never returns when a command leaves a background process holding its stdio #47350 / Bash tool never returns when a spawned command leaves a descendant holding its stdio pipes #50316. - No zombies. Zombie count was zero. (We had previously run
opencode serveas PID 1 itself and did accumulate zombie children; giving the pod a real init fixed the zombies and changed nothing about this hang.) - Not waiting on the model.
/proc/<pid>/wchanreaddo_epoll_wait, the process held no outbound connection, and our provider proxy logged no in-flight request.
So the command finished, was reaped, and the tool call still never completed.
Frequency
Intermittent, which is why there is no deterministic reproduction here: roughly 3 hangs in ~40 agent runs on one day, after ~34 consecutive runs with none — same image, same version, same kinds of command. That pattern reads like a race in spawn rather than a property of the command, consistent with the fd-ordering analysis in #29294.
Recovery note, in case it helps others
POST /session/{sessionID}/abort releases the wedged turn: the session completes normally and the transcript is kept. It is a usable watchdog action from outside.
POST /api/session/{sessionID}/interrupt returns 204 and has no effect. For the same session id, GET /api/session/{sessionID}/message returns an empty data array while GET /session/{sessionID}/message returns the full history — so the /api routes appear to address a different scope. That cost us a while to notice, and may be worth its own issue if it is not intended.
Activity
holny commentedon Sep 22, 2026
Claiming this. The race appears to be in how the shell tool receives process-exit notifications — a fast-exiting command with no descendant can miss the exit event, leaving the tool call stuck at status=running indefinitely. I'll work on a fix targeting the spawn/exit handling path in the shell tool.
CoffeePuma55644 commentedon Sep 24, 2026
I'm having exactly the same issue.
When I use OpenCode with the Next Dev Loop and the AI needs to use Agent Browser, the very first time it tries to open it, the command just runs indefinitely and never actually completes. As a result, Agent Browser is basically unusable unless I manually intervene and tell the agent to continue.
What's weird is that I never had this problem with OpenAI Codex. I'm on Windows, and when Codex used Agent Browser, everything worked perfectly fine.
With OpenCode, however, the first Agent Browser command hangs indefinitely. Once I manually tell it to continue and that first command finally completes, subsequent commands that interact with the browser work normally.
So it seems to be specifically related to how OpenCode handles the initial Agent Browser process. It's really frustrating because I now have to keep an eye on the agent to make sure it hasn't soft-locked on that first command.
holny commentedon Sep 29, 2026
Gentle nudge — open for a week, checks green, no review yet. The fix is a single latch: the drain fiber opens it on completion and the exit winner awaits it, so a fast-exiting shell command can no longer leave the call parked in status=running. Happy to rebase or adjust.
rekram1-node commentedon Oct 2, 2026
Recommend updating to opencode v2 it is much better: https://opencode.ai/v2/docs
Will do a final release for v1 soon picking up things like this but it won't be seeing too many more releases given v2 primitives are much more reliable
wthsama commentedon Oct 6, 2026
Sharing a related-but-distinct repro in case it helps disambiguate the "shell stuck running" family.
Different shape from the pipe-FD variant: here the wedged shell is caused by an orphaned grandchild reparented to PID 1 that is never reaped, so a zombie (
PPid=1, stateZ) keeps the shell entry alive.Environment: opencode 2.0.24,
opencode serveas container PID 1 (Docker, noinit: true),cat /proc/1/comm->opencode.Repro:
sh -c 'sleep 300; echo done'.kill -9 <pid of the intermediate sh>; the innersleepis orphaned and reparented to PID 1.status=runningindefinitely;docker restartclears it.Since PID 1 is the
opencodeprocess and there is no init, nothing callswait()for reparented orphans. Workaround isinit: trueon the container. Filed separately with full diagnostics: #53564.thdxr commentedon Oct 11, 2026
Thanks for the report! OpenCode 2.0 is now out and development is focused on V2, so we're closing issues filed against OpenCode 1. Please upgrade (
opencode upgrade --major, details: https://anoma.ly/notes/opencode-2-0), and if this is still relevant on 2.0, reopen this issue or open a new one with your 2.0 version.— from 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊