Skip to content

Shell tool stays status=running after a fast-exiting command with no surviving descendant (1.18.30, server mode) #50424

Closed as not planned

Description

@markussiebert

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's pause reaps 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

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

  1. holny commented on Sep 22, 2026

    @holny
    Contributor

    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.

  2. CoffeePuma55644 commented on Sep 24, 2026

    @CoffeePuma55644

    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.

  3. holny commented on Sep 29, 2026

    @holny
    Contributor

    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.

  4. rekram1-node commented on Oct 2, 2026

    @rekram1-node
    Contributor

    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

  5. wthsama commented on Oct 6, 2026

    @wthsama

    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, state Z) keeps the shell entry alive.

    Environment: opencode 2.0.24, opencode serve as container PID 1 (Docker, no init: true), cat /proc/1/comm -> opencode.

    Repro:

    1. Start a background shell whose tree has an intermediate wrapper: sh -c 'sleep 300; echo done'.
    2. kill -9 <pid of the intermediate sh>; the inner sleep is orphaned and reparented to PID 1.
    3. The orphan exits -> zombie under PID 1:
    PID   PPID  STAT  COMMAND
    2123     1   Z    [sleep]
    4712     1   Z    [sleep]
    7804     1   Z    [sleep]
    
    1. The shell/tool call stays status=running indefinitely; docker restart clears it.

    Since PID 1 is the opencode process and there is no init, nothing calls wait() for reparented orphans. Workaround is init: true on the container. Filed separately with full diagnostics: #53564.

  6. thdxr commented on Oct 11, 2026

    @thdxr
    Member

    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 𝕺𝖕𝖊𝖓𝕮𝖔𝖉𝖊

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions