Repository navigation
service: 100% CPU hang when snapshotting a very large git worktree #50734
Description
Summary
On Linux/WSL, the v2 background service hangs at ~100% CPU and stops answering HTTP when a session runs in a directory that OpenCode treats as a git project containing an extremely large number of files. The snapshot pass enumerates the entire tree on the JS thread (git ls-files --others --exclude-standard output: ~57 MB / ~1.4M paths), blocking the event loop. opencode service status then reports stopped even though the process is alive and the port is still listening.
This also creates a restart loop: if the service is killed mid-turn, the session row is left with time_suspended set; the next opencode service start auto-resumes it, repeats the same snapshot walk, and hangs again.
Environment
- opencode version: 2.0.14 (
channel=latest local=false) - OS: WSL2 Ubuntu 24.04, kernel 6.18.33.2-microsoft-standard-WSL2, WSL 2.7.14.0, Windows 10.0.26200
- Terminal: Windows Terminal (
TERM=xterm-256color) - Shell:
/bin/bash - Install/channel: latest, managed binary at
~/.opencode/bin/opencode - Active plugins: local plugin
./plugins/caveman/plugin.js; remote MCP serverfaces. Both were removed for a control run (cleanXDG_CONFIG_HOME) and the hang still reproduced.
Reproduction
- In a home directory with ~1.4M files, create an empty git repo:
git init ~(0 commits, no remote, no.gitignore). opencode service start— starts fine and prints its URL.- Open a session in
~, or restart the service after a home-dir session was interrupted mid-turn so it is auto-resumed at startup. - The service spawns:
git --git-dir ~/.local/share/opencode/snapshot/global/<hash> --work-tree ~ ls-files --others --exclude-standard -z -- .
and then blocks.
Expected Behavior
- The service stays responsive while snapshotting.
- Very large directory walks are capped, skipped, or performed off the main thread.
- A stalled session resume backs off instead of pinning the server.
service statusdistinguishes "busy/hung" from "stopped".
Actual Behavior
- Process alive, port listening (
ssshows Recv-Q 9–14 on the listener),/api/infotimes out, ~100% CPU for minutes. opencode service statusprintsstopped.- Log output stops right after the snapshot
ls-filesentry; nothing further is written. - After a mid-turn kill,
session_v2has a row with non-nulltime_suspendedand an incrementedresume_attempts; every restart immediately hangs again.
Additional Context
Control tests:
- Fresh empty DB with the same config → service healthy.
- Copy of the affected DB (
VACUUM INTOcopy) → healthy after clearingtime_suspendedon the affected session; hangs again as soon as a home-dir session is resumed. - Suspended session in a normal repo (~158k files) → resumes fine, stays responsive.
Measurements:
- Home directory: 1,458,088 files.
git ls-files --others --exclude-standard -zoutput: 56,875,543 bytes; manual walk takes ~3 s, and JS-side processing of the result blocks far longer.- Self-referential snapshot: the snapshot store lives inside the worktree (
~/.local/share/opencode/snapshot/...), and its own walk lists 1,476 files from the store. - DB was 1.24 GB with 246,133 free pages out of 303,277;
VACUUMshrank it to 229 MB. Not the root cause, but it also slowed startup.
Log excerpt (service boot, then silence after the snapshot command):
timestamp=... run=2f1c16c4 message="spawning process" command=git args="[\"rev-parse\",\"--git-dir\",\"--git-common-dir\",\"--show-toplevel\"]" cwd=~ role=server
timestamp=... run=2f1c16c4 message="spawning process" command=git args="[\"--git-dir\",\"~/.local/share/opencode/snapshot/global/a9dfd4ad...\",\"--work-tree\",\"~\",\"diff-files\",\"--name-only\",\"-z\",\"--\",\".\"]" cwd=~ role=server
timestamp=... run=2f1c16c4 message="spawning process" command=git args="[\"--git-dir\",\"~/.local/share/opencode/snapshot/global/a9dfd4ad...\",\"--work-tree\",\"~\",\"ls-files\",\"--others\",\"--exclude-standard\",\"-z\",\"--\",\".\"]" cwd=~ role=server
timestamp=... run=2f1c16c4 message="mcp connected" server=faces tools=25 role=server
-- no further entries until the next manual `service status` invocation --
Additional observations:
- Two stale project rows with worktree
/repeatedly logworktree discovery failed directory=/ strategy=git error=Worktree.DirectoryUnavailableError. - Workaround that stopped the hang: renaming the junk empty
~/.git(no commits, no remote) removed the home-dir snapshot walk; the service has stayed healthy since (CPU ~3%).
Activity
github-actions commentedon Sep 22, 2026
This issue might be a duplicate of existing issues. Please check:
git add --sparse --pathspec-from-file=-hangs indefinitely blocked on stdin (not a zombie — process stays alive inSsstate) #41648: Desktop: snapshot'sgit add --sparse --pathspec-from-file=-hangs indefinitely — related snapshot hang issueYour workaround (renaming
~/.gitto remove the home-dir as a git project) matches the one found by others in #32981. You may want to add your detailed measurements and restart-loop findings as a comment on #32981 since they add valuable new context about the issue.jonaspm commentedon Sep 22, 2026
Cross-posted the V2 measurements and the restart-loop findings to the canonical thread: #32981 (comment)
Leaving this issue open for now since the V2 background-service failure mode (service unresponsive + service status reporting stopped + auto-resume restart loop) differs from the V1 TUI freeze. Say the word if you would rather have it closed as a duplicate.
neriousy commentedon Oct 20, 2026
Thanks for the detailed report. Version 2.0.26 removes quadratic snapshot path processing that could lock up the service on very large worktrees.
Update with
opencode upgradeornpm i -g @opencode/cli@latest(desktop: update the app).Please comment or reopen if the service still hangs with your worktree on that version or newer.