anomalyco / anomalyco/opencode

bug: workspace diff passes --unified=2147483647, re-emitting the file once per hunk (>1 GB patch text, ~11 s CPU per filesystem event)

Open
#49,267 4 comments 0 reactions 1 assignee View on GitHub

@Brendonovich is already working on this.

Since Sep 16, 2026.

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

Description

Description

无法直接提交:本机没有 gh、没有 GitHub token,且 github.com web 被墙(api.github.com 可达但建 issue 需鉴权)。已把报告写成即用文件,并确认了更新通道就是 anomalyco/opencoderesources/app-update.yml)。

报告已存:C:\Users\Admin\AppData\Local\Temp\opencode\opencode-issue-unified-context.md

标题bug: workspace diff passes --unified=2147483647, re-emitting the file once per hunk (>1 GB patch text, ~11 s CPU per filesystem event)

正文


Environment
OpenCode Desktop 1.18.31 (@opencode-aidesktop, update channel anomalyco/opencode per resources/app-update.yml)
OS Windows 10 企业版 10.0.19042, x64
git 2.37.1.windows.1
node v24.13.0
workspace 10 modified tracked files, two of them generated JSON (1.34 MB / 0.85 MB)
Summary

Every filesystem event in the workspace makes OpenCode spawn a full-context working-tree diff:

git --no-optional-locks -c core.autocrlf=false -c core.fsmonitor=false -c core.longpaths=true \
    -c core.symlinks=true -c core.quotepath=false diff --patch --no-ext-diff \
    --no-renames --unified=2147483647 HEAD -- .

With --unified=INT32_MAX the hunks are not merged, and every hunk's context is unbounded. git therefore re-emits a large slab of the file once per changed cluster, so output scales as O(changed clusters × file size).

Measured here: one invocation produced >1 GB of patch text and ~11 s of CPU; OpenCode's node utility process held 60–88% CPU with up to 10 concurrent git.exe alive (29 distinct git PIDs in a 30 s window), each spawning a child git.exe.

Steps to reproduce
  1. Have a workspace containing a large-ish tracked file that is modified (a few hundred changed clusters in a 1–2 MB file is enough).
  2. Edit/touch any file in the repo (a bare touch — mtime only, content unchanged — is sufficient; verified).
  3. Observe repeated git ... diff --patch --no-ext-diff --no-renames --unified=2147483647 HEAD -- . spawned by the OpenCode node utility process (--type=utility --utility-sub-type=node.mojom.NodeService), piling up.
Measurements

Same command, per modified file (stdout byte count):

file size changed lines changed clusters (-U0) output with --unified=2147483647
level_curriculum.json 1.34 MB 3049 / 1786 1747 512 MB
knowledge_points.json 0.85 MB 243 / 243 243 213 MB
content_assets_poems.json 0.14 MB 126 / 126 126 18.3 MB
content_assets_english.json ~0.1 MB 65 / 65 65 2.8 MB

Whole repo (same command, -- .): >1024 MB / ~11000 ms (truncated by a 1 GiB capture buffer, so the real figure is larger).

Control — same repo, same files, plain -U3 diff: 0.15 MB / 125 ms for the same file. So the flag inflates output ~1800× per file and wall time ~88×.

Why the flag does not behave as intended

--unified=2147483647 looks like "give me the whole file as context". But git merges two change clusters only when the gap between them is ≤ 2 × context. 2 × 2147483647 overflows a signed 32-bit int → negative → the merge condition can never hold, so no hunks merge, while each hunk's context stays unbounded. Net effect is the worst of both worlds: maximum output, zero consolidation.

(I have not read git's source to point at the exact overflow site; the behaviour is reproducible with stock git 2.37.1.windows.1. Note that a bounded-but-huge value such as --unified=100000 would already merge all clusters in these files while still covering the whole file — so the current value is not merely large, it is self-defeating.)

Impact
  • A per-event CPU storm, not per-commit: any repo with a few large tracked files is affected.
  • Watcher events are frequent and cheap (build output, test reports, sqlite WAL writes, logs, touch), so the storm sustains itself while any tool writes into the repo.
  • Long sessions are worst: each invocation takes seconds, so successive spawns overlap and process count / CPU climb instead of settling.
  • Memory: each invocation materialises up to ~1 GB of patch text in the child process and again over IPC in the renderer.
  • The workaround users are pushed to is to change the repo (e.g. .gitattributes -diff on generated files) to compensate for an app-side flag — which also destroys diff readability for those files.
Suggested fixes
  1. Don't pass an unbounded/overflowing context value. Either clamp it (to the file's line count, or a few thousand), or implement "whole file" by emitting the file body once instead of once per hunk.
  2. Guard by size: skip or bound the diff when additions + deletions or the blob size crosses a threshold — same spirit as the diffFull guard in #48617.
  3. Single-flight / cache this diff per event burst and debounce so N rapid writes cause one invocation, not N — same spirit as #44127's TTL + single-flight work.
  4. Consider an env escape hatch (consistent with the existing OPENCODE_VCS_* knobs).
Related issues
  • #3176 — "Why is OpenCode massively abusing git?" (same broad symptom)
  • #44127 — redundant git subprocess spawns (spawn count; this report is about per-spawn output size)
  • #48617 — snapshot.diffFull memory exhaustion on large files (in-process Myers diff; different code path from the git diff subprocess)
  • #43769 — Windows CPU under parallel sessions
  • #48638 — durable event write amplification from turn diffs

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

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.