Description
Related: #35870 (headless hang at startup, ZIO lost-wakeup hypothesis), #38201 (same project copy refresh started signature, large binaries), #48848 (cross-process gap in snapshot/git ops). None of these cover the repro below: a second concurrent instance for the same git project deterministically stalls one of them, and the wait is observable as a zombie git rev-parse whose JS await never resumes.
Version: opencode 1.18.31 (standalone binary, embeds Bun v1.3.14)
OS: Linux 6.1.0-42-amd64 (Debian), x86_64, running as root
Repro rate: consistent while a first instance is alive for the same repo
Summary
If one opencode instance (e.g. a TUI session) is running for a git project, starting a second instance for the same project hangs forever, silently: no response, no error, no timeout, no log output. The hang only occurs when the project contains a .git directory; non-git projects are unaffected.
Reproduction
# terminal 1 (stays open)
cd /path/to/any-git-repo
opencode # TUI, idle is enough
# terminal 2
cd /path/to/any-git-repo # or any subdirectory, or a linked worktree of the same repo
opencode run "say hi" # hangs forever — no output whatsoever
- Works: second instance in a directory without
.git.
- Works: second instance in a different git repo.
- Fails: same repo (common dir), including from subdirectories / worktrees.
Observed behavior (failing instance)
opencode run blocks indefinitely; process main thread parked in rt_sigsuspend (permanent await).
- Log ends at
project copy refresh started (projectID=…), after init count=5. No process / stream events ever appear.
- DB: the session is created but stays at 0 tokens, 0 parts, no
finishReason.
- No outbound network, no TCP port bound, no lock held on the opencode DB (external
BEGIN IMMEDIATE writes succeed during the hang).
- Killing the first instance (or waiting for it to exit) lets the blocked one proceed.
Evidence gathered (strace -f, /proc, binary analysis)
- During refresh, opencode runs a fixed sequence of
git coprocesses. One of them — git rev-parse --git-common-dir — is left as a zombie: it has exited 0, wait4 succeeds in the trace, yet the JS fiber awaiting it never resumes.
- Strace shows repeated re-spawns of the same command ~1 s apart (timeout/retry loop on a fiber that never completes), the main thread blocked on futex, and the worker pool expanding (45×
clone3(CLONE_THREAD)) until nothing progresses.
- The same command run manually completes in ~6 ms. Raw Bun coprocess spawning (
git rev-parse, 3 concurrent, stdin:"ignore") works fine in Bun 1.3.13.
- Bisected the project directory contents:
.git is the sole trigger (a dir with only AGENTS.md or only opencode.json does not hang).
- The hang reproduces with a completely fresh
XDG_DATA_HOME/XDG_STATE_HOME/HOME (not state-dependent), and with strace -f attached (which adds overhead) it fails more often than without — consistent with a race.
- MCP servers, auth, and the message path were all verified healthy and are not involved (failure predates any model/network activity).
Expected behavior
A second instance for the same project should either:
- fail fast with a clear message (
opencode is already running for this project (pid …, cwd …)), or
- report/attach to the existing session.
A silent infinite hang with exit-code ambiguity is the worst failure mode: the process must be killed by hand.
Workaround
Keep exactly one opencode session per git repository (or per repo common dir, since worktrees share it). Guard script used here: /usr/local/bin/opencode.sh — scans running opencode processes' /proc/*/cwd, resolves the git common dir, and refuses to start a second instance for the same project.
Hypothesis (labeled as such)
The refresh pipeline runs its git coprocesses through the shared Bash service; the completion of one of those child processes is lost (child exits and is reaped at OS level, but the JS-side await never fires), and a retry loop keeps re-spawning without ever completing — i.e. a coprocess-completion notification race in the runtime/service layer, worsened (but not caused) by concurrency. Confirming/fixing the actual mechanism is left to the maintainer; the evidence above narrows it to the coprocess await during project refresh.
Plugins
No response
OpenCode version
1.18.31
Steps to reproduce
No response
Screenshot and/or share link
No response
Operating System
No response
Terminal
No response
Description
Related: #35870 (headless hang at startup, ZIO lost-wakeup hypothesis), #38201 (same
project copy refresh startedsignature, large binaries), #48848 (cross-process gap in snapshot/git ops). None of these cover the repro below: a second concurrent instance for the same git project deterministically stalls one of them, and the wait is observable as a zombiegit rev-parsewhose JS await never resumes.Version: opencode 1.18.31 (standalone binary, embeds Bun v1.3.14)
OS: Linux 6.1.0-42-amd64 (Debian), x86_64, running as root
Repro rate: consistent while a first instance is alive for the same repo
Summary
If one opencode instance (e.g. a TUI session) is running for a git project, starting a second instance for the same project hangs forever, silently: no response, no error, no timeout, no log output. The hang only occurs when the project contains a
.gitdirectory; non-git projects are unaffected.Reproduction
.git.Observed behavior (failing instance)
opencode runblocks indefinitely; process main thread parked inrt_sigsuspend(permanent await).project copy refresh started(projectID=…), afterinit count=5. Noprocess/streamevents ever appear.finishReason.BEGIN IMMEDIATEwrites succeed during the hang).Evidence gathered (strace -f, /proc, binary analysis)
gitcoprocesses. One of them —git rev-parse --git-common-dir— is left as a zombie: it has exited 0,wait4succeeds in the trace, yet the JS fiber awaiting it never resumes.clone3(CLONE_THREAD)) until nothing progresses.git rev-parse, 3 concurrent,stdin:"ignore") works fine in Bun 1.3.13..gitis the sole trigger (a dir with onlyAGENTS.mdor onlyopencode.jsondoes not hang).XDG_DATA_HOME/XDG_STATE_HOME/HOME(not state-dependent), and withstrace -fattached (which adds overhead) it fails more often than without — consistent with a race.Expected behavior
A second instance for the same project should either:
opencode is already running for this project (pid …, cwd …)), orA silent infinite hang with exit-code ambiguity is the worst failure mode: the process must be killed by hand.
Workaround
Keep exactly one opencode session per git repository (or per repo common dir, since worktrees share it). Guard script used here:
/usr/local/bin/opencode.sh— scans runningopencodeprocesses'/proc/*/cwd, resolves the git common dir, and refuses to start a second instance for the same project.Hypothesis (labeled as such)
The refresh pipeline runs its
gitcoprocesses through the shared Bash service; the completion of one of those child processes is lost (child exits and is reaped at OS level, but the JS-side await never fires), and a retry loop keeps re-spawning without ever completing — i.e. a coprocess-completion notification race in the runtime/service layer, worsened (but not caused) by concurrency. Confirming/fixing the actual mechanism is left to the maintainer; the evidence above narrows it to the coprocess await during project refresh.Plugins
No response
OpenCode version
1.18.31
Steps to reproduce
No response
Screenshot and/or share link
No response
Operating System
No response
Terminal
No response