anomalyco / anomalyco/opencode

Instance bootstrap hangs forever (Linux): spawned git child exits but is never reaped — TUI renders, but Enter can never start a session

Open
#41,806 3 comments 0 reactions 1 assignee View on GitHub

@jlongster is already working on this.

Since Aug 11, 2026.

Dominant language
TypeScript
Stars
209k
Forks
27.5k
PR merge metrics
PR metrics pending

Description

Summary

On Linux, opencode (TUI) intermittently hangs forever during instance bootstrap: a git child spawned during init exits but is never reaped (it stays <defunct> for the life of the process), the bootstrap await never settles, and the window renders normally — accepts typing — but Enter can never start a session because the server side never finished booting. No error is shown or logged; the process idles in epoll indefinitely.

Environment

  • opencode 1.18.15, Linux 6.8.0-124-generic (Ubuntu), TUI launched in a terminal
  • Heavily concurrent host: multiple opencode instances (interactive + opencode run) active in the same projects

Evidence (from two live hung instances, same day)

Log (shared ~/.local/share/opencode/log/opencode.log) — the hung instance run stops mid-bootstrap and never logs another line:

Instance A stopped at init:

16:33:51.880 bootstrapping directory=/home/oren/projects/kk/billie
16:33:52.020 message="all LSPs are disabled"
16:33:52.021 message="all formatters are disabled"
16:33:52.021 message=init
                      <- nothing, ever again (14 lines total, 0 sessions)

Instance B stopped one phase later:

16:40:13.397 message=init
16:40:16.163 message="watcher backend" ... backend=inotify
16:40:16.165 message="project copy refresh started" projectID=1d4fe22...
                      <- never "done", nothing again (0 sessions)

A healthy boot of the SAME project in the SAME minute continues: initwatcher backendproject copy refresh started/doneinit count=281 → sessions created on Enter.

Process table — the discriminator. Each hung instance holds exactly one unreaped git child; seven healthy same-host instances hold zero:

$ ps --ppid <hung-tui-pid> -o pid,stat,args
3377914 Sl+  python3 .../mcp_server.py     (local MCP, alive, fine)
3378581 Zs   [git] <defunct>               (spawned during bootstrap, never reaped)

The zombies' spawn times match the last log line to the second (e.g. git spawned 16:40:16 local; project copy refresh started logged 16:40:16.165Z). Parent state: wchan=ep_poll, i.e. the event loop is alive and waiting — an await whose completion event was lost, not a deadlock on a sync call.

Trigger correlation

Both hangs happened when the window was opened into a project where other opencode instances were concurrently running git against the same shared snapshot store (~/.local/share/opencode/snapshot/<projectID>/ — visible as concurrent tracking hash=... log lines from the other instances). It is a race: a boot into the same busy project 90 s earlier survived. Historical scan of our log: ~30 instance runs since 2026-08-07 (of 895) logged creating instance but never reached watcher backend, clustered in bursts of concurrent activity.

What it is not

  • Not input/keybind/TTY related — termios verified sane; the failure is server-side, before any input matters.
  • Not plugins spawning the git — our plugins only spawn git synchronously (execFileSync, which reaps its own child). The unreaped child is core's.
  • Not resolved by any key — only closing and reopening the window.

Expected

Bootstrap either completes or fails loudly. A spawned git child's exit should always settle the awaiting promise (success or error), under any interleaving — including exiting very fast, or failing on index.lock contention from a sibling instance.

Suspected area

The boot-time snapshot/project-copy git spawn: child exit (possibly an immediate/fast exit, or a nonzero exit on lock contention) is not observed — either the exit handler is registered after the exit event has already fired (Bun subprocess reaping race) or an error path never rejects the awaited promise. Happy to run an instrumented build or provide more process-level captures; reproduction should be possible by booting a TUI into a project while a loop hammers git operations against that project's snapshot dir.

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.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.