Multi-diff editor renders phantom repeated file headers (wrong row identity) after scrolling a ~30-file diff
- Dominant language
- TypeScript
- Stars
- 193k
- Forks
- 42.4k
- PR merge metrics
- PR metrics pending
Description
Type: Bug
VS Code version: 1.129.0 and 1.129.1 (both affected)
OS version: macOS 15.5 (Darwin 25.5.0), Apple Silicon, external 4K display (BenQ EW3270U)
### Summary
The multi-diff editor (opened via the `vscode.changes` command) intermittently corrupts its virtualized rows **after scrolling** a diff with ~30+ resources: many rows render with the **same file header repeated** (one file's basename/dirname/status badge shown 10–20 times) at sliver heights (~35 px), interleaved with thin slices of *other* files' content. Which file becomes the "phantom" repeated header **changes with scroll position**. Clicking into / settling on a row renders that file perfectly; closing and reopening the multi-diff editor always clears the corruption.
### Steps to reproduce
1. An extension opens a multi-diff via `vscode.changes` with ~35 triples `[label, original, modified]` whose sides are URIs of a registered `TextDocumentContentProvider` (custom scheme; every document resolves promptly and correctly — initial render is clean and fully expanded).
2. Scroll up and down through the multi-diff for a while (mouse wheel, varying speed).
3. Observe rows collapsing into repeated phantom headers of a single file with sliver-height content slices from unrelated files.
Synthetic content generator we used (any repo shape with ~35 modified/added/deleted files of a few hundred lines reproduces the input):
```bash
mkdir soup-repo && cd soup-repo && git init -q
for i in $(seq 1 35); do mkdir -p "mod$((i%7))"; { echo "# module $i"; for l in $(seq 1 220); do echo "function fn_${i}_${l}() { return ${l}; } // line ${l}"; done; } > "mod$((i%7))/file_$i.js"; done
git add -A && git commit -qm base
for i in $(seq 1 30); do f="mod$((i%7))/file_$i.js"; sed -i '' "s/return 5;/return 500;/" $f; echo "// appended $i" >> $f; done
for i in 31 32; do rm "mod$((i%7))/file_$i.js"; done
for i in 36 37 38; do echo "// new $i" > "mod$((i%7))/new_$i.js"; done
git add -A && git commit -qm head
```
then, in an extension host, open triples built from `git diff --name-status -z HEAD~1 HEAD` (original = `HEAD~1` side, modified = `HEAD` side, `undefined` sides for A/D) via `vscode.commands.executeCommand("vscode.changes", title, triples)`.
### Observations
- Reproduced on two different days (1.129.0, then 1.129.1 after updating) in a long-lived window; both times only **after scrolling** — the initial render is always correct.
- A fresh instance (`@vscode/test-electron`, only our development extension loaded) given the identical 32-file input rendered cleanly at open; we have not yet caught the corruption in that clean instance, which suggests scroll history / window lifetime is a factor.
- The phantom header's identity tracks scroll position (near the top it repeats an early file, mid-list it repeats a mid-list file, etc.), which smells like the virtualization pool re-binding row templates without updating the header `ResourceLabel` / heights (`src/vs/editor/browser/widget/multiDiffEditor/multiDiffEditorWidgetImpl.ts` ObjectPool + placeholder-height path).
- Rebuilding the editor (close + `vscode.changes` again) reliably clears it; `multiDiffEditor.expandAll` / `collapseAll` do not.
- Our original screen recording shows proprietary code, so it isn't attached; happy to run instrumented builds or provide further diagnostics on request.
Contributor guide
Assessment
This issue has not been assessed yet.