Repository navigation
Description
Description
On the latest release (opencode v2.0.27, npm @opencode/cli), the snapshot internal git repository grew from nothing to 15 GB in ~11.5 hours of normal agent use on a small project, filling the entire 40 GB root filesystem (100% used) and breaking all write operations on the host.
This is not the 2MB-large-file problem fixed in 0a80ef4 (per #17753). The tracked content here is ordinary small source files. The bloat is loose-object accumulation plus leaked tmp_obj_* / tmp_pack_* garbage — i.e. the hourly maintenance gc either never runs on these repos or fails silently, so nothing ever gets packed/pruned.
Environment
- OpenCode: v2.0.27 (npm latest as of 2026-10-13; latest GitHub release v1.19.0)
- OS: Ubuntu 24.04 (Lighthouse VM), ext4, 40 GB root
- Data dir:
~/.local/share/opencode/snapshot/<project-hash>/<repo-hash>/
Evidence (captured live during the incident)
git count-objects -vH inside the snapshot repo:
count: 334485 # 334k LOOSE objects — gc clearly never completed
size-pack: 6.68 GiB # plus 6.68 GiB of packs (incl. leaked tmp_pack)
git gc --prune=now reported dozens of garbage files before being interrupted:
warning: garbage found: objects/pack/tmp_pack_odfHeH
warning: garbage found: objects/7a/tmp_obj_IrvBmH
warning: garbage found: objects/a7/tmp_obj_wN3ApW
... (100+ tmp_obj_* files across objects/a7/, objects/b7/, etc.)
Timeline: snapshot dir created 2026-10-12 23:55 (session start) → 15 GB by 2026-10-13 11:13 → df / at 100%. The workspace itself is < 1 GB.
Why the existing mitigations don't cover this
- 0a80ef4 (2 MB file size cap) — irrelevant here; all tracked files are small.
- Hourly
git gc --prune=7.daysscheduler (per Snapshot feature consumes excessive disk space (170GB+ in my case) #17753 discussion) — evidently not effective: 334k loose objects after 11.5 h means repacking never happened (or the scheduler gc targets a different repo path / fails silently when the repo has dubious-ownership or lock issues). tmp_obj_*files (not justtmp_pack_*) are also leaked — Snapshot system leaks tmp_pack_* files indefinitely, filling disk at ~9.5 GB/hour #14811 coveredtmp_pack_*, but loosetmp_obj_*garbage underobjects/xx/is still left behind when a snapshot write is interrupted.
Impact
Root filesystem exhaustion → total loss of shell/tooling on the host (any command that writes temp files fails). Had to rm -rf ~/.local/share/opencode/snapshot to recover.
Suggested fixes
- Run (or re-verify) the maintenance gc inside the snapshot repo with explicit
git -C <repo>and ownership-safe config, and log failures instead of swallowing them. - Clean up
tmp_obj_*loose garbage in the maintenance pass, not onlytmp_pack_*. - Add a hard disk-usage cap for the snapshot dir (e.g. default 1–2 GB, configurable), with LRU pack pruning when exceeded — a warning alone (fix(snapshot): add disk space warning when snapshot grows large #17811) is not enough on small VMs.
- Consider
gc.autotuning or--geometric-repackafter each snapshot commit burst.
Workaround applied
"snapshot": false in ~/.config/opencode/opencode.jsonc + weekly guard script running git gc/size-cap on the snapshot dir.
Happy to provide the full count-objects -vH, directory listing, or re-run experiments on demand.
Activity
opencode-agent commentedon Oct 13, 2026
Thanks for the detailed numbers, they help a lot.
One note first: v2 doesn't run the hourly
git gc --prune=7.daysthat #17753 and #14811 refer to (that was v1). In v2.0.27, after a snapshot capture, OpenCode checks at most every 10 minutes and packs loose objects once there are 2048 or more. If packing fails, it logs a warning:failed to pack snapshot objects. Having 334k loose objects means that packing either failed again and again or never ran. To find out which, could you share:failed to pack snapshot objectsorfailed to capture snapshotlines from that session (OpenCode's log files), with the error text that follows them. If there are many, one or two examples is enough.node_modules, build output) ignored in.gitignore?git count-objects -vHoutput, and roughly how manytmp_obj_*andtmp_pack_*files there were.You can reply here or edit the issue. If you edit it, please also leave a short comment saying you've updated it, so we know you're done.
Related issues, ordered from most to least likely to be relevant (none looks like the same problem):
tmp_pack_*slamdunk111 commentedon Oct 13, 2026
Thanks for the fast triage — here's everything requested.
1. Logs
From
~/.local/share/opencode/log/opencode.log(sessionrun=95d0bef5, log starts2026-10-12T15:54:21Z):Important nuance:
failed to pack snapshot objectsappears exactly once in the whole log, at 01:21Z — i.e. after the disk was already full. So packing was not "failing again and again" beforehand; it was logging no errors while loose objects still accumulated to 334k. The disk-full errors are a consequence, not the cause.2. The workload
This is, I think, the key finding:
/home/ubuntu— the home directory itself (log showscwd=/home/ubuntuin 537 entries; the actual project being worked on was/opt/one-api-new, a small one-api deployment dir)./home/ubuntuhappens to be a git repository (2095 tracked files, 1888 dirty entries at last check, no.gitignore), and it contains.npm,.cache,.nvm,.local/share/opencode/opencode.db(+-wal), go build caches, etc. — constantly-churning files totaling several GB./home/ubuntu, GIT_DIR =/home/ubuntu/.local/share/opencode/snapshot/<project-hash>/<repo-hash>/. If the capture does not exclude its own data directory, every capture commits the previous captures' loose objects and packs — a self-ingesting feedback loop. That would fully explain 15 GB / 11.5 h from a <1 GB project, and why packing "succeeded" (no warnings) yet loose objects exploded: each cycle re-commits the snapshot store's own churn.opencode serve --serviceprocess + interactive TUI, ~8 distinctrun=ids over the 11.5 h window, single user, no worktrees, no parallel subagents that I know of.Could you confirm whether the v2 capture excludes the OpenCode data directory (or anything under
~/.local/share/opencode/) when it falls inside the tracked worktree? If not, that's likely the root mechanism here, and running opencode from$HOMEis probably a common user pattern worth guarding against (e.g. always exclude the data dir, or refuse to snapshot$HOME).3. Object counts (captured live before cleanup)
git count-objects -vHinside the snapshot repo:Garbage found by
git gc(full warnings, before I interrupted it): 79tmp_obj_*files (spread acrossobjects/a7/,objects/b7/,objects/7a/,objects/7c/,objects/ae/,objects/b7/…) and 1tmp_pack_*file (objects/pack/tmp_pack_odfHeH).Note the
tmp_obj_*garbage specifically: these sit underobjects/xx/as loose-object temp files, so a maintenance pass that only sweepstmp_pack_*(per #14811) would never clean them.Recovery note
I had to
rm -rf ~/.local/share/opencode/snapshotto recover the host, so the repo itself is gone — the numbers above are from live captures during the incident. Workaround now in place:"snapshot": falseinopencode.jsoncplus a weekly guard script (gc + size cap) as defense in depth.Happy to run a controlled repro (opencode from
$HOMEon a scratch VM with a disk quota, logging capture/pack cadence) if that would help pin the self-capture hypothesis down.opencode-agent commentedon Oct 13, 2026
Thanks for the details, your guess was right. I reproduced this on the latest
dev(c1615b1). The snapshot code there is the same as in v2.0.27.When the project's git worktree contains OpenCode's data directory (here because
$HOMEis a git repo with no.gitignore), each snapshot capture also records the snapshot store's own files: its new loose objects, temporary index files and pack files under 2 MB. The script below recreates that layout and runs 12 captures, each changing only one line in one file:The capture only filters by the project's ignore rules and the 2 MB limit on untracked files. Nothing excludes the snapshot directory itself. Separately, leftover
tmp_obj_*files underobjects/xx/are never cleaned up; onlytmp_pack_*files are.Until this is fixed, besides
"snapshot": falseyou can add.local/share/opencode/(or a broader rule, like.local/and.cache/) to a.gitignorein your home repo, or start OpenCode from the actual project directory (/opt/one-api-new) instead of$HOME.Related: #16336 (v1, huge snapshot storage when started in the home directory) and #36093 (v2 snapshot retention policy).
Reproduction script (selfcapture.test.ts)
Run it:
bun selfcapture.test.tsslamdunk111 commentedon Oct 13, 2026
Great — glad the self-capture hypothesis held up, and thanks for the reproduction script and the extra workarounds.
Status on my side:
"snapshot": false+ a weekly guard script (gc + size cap on the snapshot dir) are already deployed on the affected host, so the acute risk is covered..local/,.cache/,.npm/and.nvm/to a.gitignorein the$HOMErepo as belt-and-braces. One caveat we noticed: ~231 files under those dirs were already tracked in the home repo, and ignore rules don't apply to tracked files — so this only stops new churn; fully de-tracking them would needgit rm --cached, which I've left alone for now.Two follow-up questions, no urgency:
tmp_obj_*in the maintenance pass? If so, I'll keep this issue open as the tracking reference for my notes.Happy to re-test on a scratch VM once a fix lands.