[BUG] Scrollback duplication on terminal resize persists in 2.1.116 (VS Code integrated terminal, macOS)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Update (2026-04-26)
This issue was originally filed against macOS + VS Code, but reports in this thread confirm it is not platform-specific and not VS Code-specific. Reframing scope and consolidating findings at the top. Original report preserved below.
Confirmed reproductions
- macOS + VS Code integrated terminal (original report, also @Danielevko)
- Linux + tmux + alacritty (@napter)
- Linux + tmux + kitty (@igor47)
- Linux + tmux + xterm.js web client (@eyalev)
- Windows Terminal, legacy
conhost.exe, Linux Mint + gnome-terminal (@NatanaelRibF) - Windows, generic (@cesarvarela)
Regression bisected to 2.1.101
@eyalev ran a deterministic harness across every native build on downloads.claude.ai from 2.1.100 → 2.1.119:
| Version | Leak count on 6 resizes |
|---------|--------------------------|
| 2.1.100 | 0 (clean) |
| 2.1.101 | 6 (regression lands) |
| 2.1.116 | 6 (claimed fix — unchanged) |
| 2.1.119 | 6 (current) |
The 2.1.116 changelog entry "Fixed scrollback duplication" does not address this variant. Last known-good version is 2.1.100 (2026-04-10).
Triggers (broader than resize)
The duplication fires on any main-screen redraw event, not just SIGWINCH:
- Terminal resize
- Output bursts that exceed pane height
※ recap:away-summary block rendering on session resume- Input prompt state transitions (e.g. vim-mode
-- INSERT --indicator appearing/disappearing)
Suspected cause (per @napter)
Ink's redraw emits cursor-up + erase-line to rewind over the previous frame. When the dynamic region is taller than the viewport, cursor-up saturates at the top of the viewport — content that has already scrolled off cannot be erased. The next frame appends at the bottom and pushes one pane-height of un-erased content into scrollback. N redraws → N duplicates, spaced by pane height. Full-height panes that fit the entire dynamic region do not duplicate, consistent with the saturation theory.
Workarounds, ranked
| Workaround | Effect | Cost |
|---|---|---|
| Downgrade to 2.1.100 | Fully clean | Lose newer features |
| "tui": "fullscreen" in ~/.claude/settings.json | Eliminates leak (alt-screen renderer doesn't touch scrollback) | Laggier line-by-line scrolling, no native scrollback |
| "awaySummaryEnabled": false | Removes the recap trigger only | Doesn't fix resize or large-output triggers |
Confirmed not to help
- VS Code GPU acceleration /
useAtlasEngine: falseon Windows Terminal - Shell choice (zsh / bash / pwsh / cmd / Git Bash)
- Shell integration on/off
- Custom statusLine on/off
editorMode(vim vs normal)- Font ligatures, integer fontSize, zero letterSpacing
- Scrollback buffer size
- Terminal smoothing / accessibility settings
Related issues
#51418, #46834, #52825, #52924, #52027, #52547, #52124
Ask
- Re-triage as cross-platform (remove platform-specific labels)
- Reopen if closed against the 2.1.116 fix
- Diff 2.1.100 → 2.1.101 in the Ink / main-screen renderer path
---
Original report
The scrollback duplication on resize bug noted as fixed in v2.1.116 still reproduces in my environment. Each terminal resize during a Claude Code session pushes a full snapshot of the current TUI into terminal scrollback. Multiple resizes produce stacked duplicates of the splash screen / current view.
The fix from v2.1.116 ("Fixed scrollback duplication in inline mode where resizing the terminal or large output bursts would repeat earlier conversation history") appears to be incomplete for this environment combination.
Likely related to / possible duplicate of #18493.
Environment
- Claude Code: 2.1.116
- VS Code: 1.116.0 (integrated terminal, panel location)
- OS: macOS 26 (Darwin 25.4.0)
- Hardware: Apple Silicon
- Shell: zsh (default macOS, minimal
.zshrc— PATH exports only, no custom prompt) - Terminal font: JetBrainsMono Nerd Font Mono
- TUI mode:
default(the bug does not occur withtui: "fullscreen")
What Should Happen?
Expected: Scrollback shows whatever was in the shell before claude was launched.
Error Messages/Logs
**Actual:** Scrollback contains multiple stacked duplicates of the Claude splash screen, separated by stray characters (e.g. `)`).
The bug appears on the splash screen with zero user input, ruling out hooks, statusline, or any per-turn behavior.
Steps to Reproduce
Reproduction
- Open VS Code integrated terminal
- Run
claudeto start a fresh session - Before sending any prompt, resize the terminal panel several times (drag the panel border, or toggle panel maximize)
- Scroll up in the terminal
Cross-platform reproducer (per @napter, Linux + tmux):
- Split a tmux pane so Claude Code runs in a pane ~50 lines tall
- Prompt a response that emits long tool-call output (e.g. a git commit with a HEREDOC message ≥60 lines, or a large diff)
tmux capture-pane -p -S -50000after the response completes — same content block repeats at intervals matching pane height
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
2.1.100 (regression introduced in 2.1.101, 2026-04-10)
Claude Code Version
2.1.116 (also reproduced on 2.1.117, 2.1.118, 2.1.119)
Platform
Anthropic API
Operating System
macOS (also reproduced on Linux and Windows — see Update section above)
Terminal/Shell
VS Code integrated terminal (also reproduced in alacritty, kitty, Windows Terminal, conhost, gnome-terminal, xterm.js)
Additional Information
Workaround
Setting "tui": "fullscreen" in ~/.claude/settings.json eliminates the glitch (alt-screen renderer doesn't touch scrollback). However, scrolling inside fullscreen mode is line-by-line and feels noticeably laggier than native xterm.js scrolling, so it isn't a comfortable permanent solution for heavy terminal users.
The cleanest workaround is downgrading to 2.1.100 until the renderer regression is addressed.
Ruled out (not the cause)
Exhaustively eliminated as causes across multiple reporters and platforms:
- VS Code
terminal.integrated.gpuAcceleration(on,off,auto— same) - VS Code
terminal.integrated.shellIntegration(disabled — same) - VS Code
terminal.integrated.suggest.enabled(disabled — same) - VS Code
terminal.integrated.stickyScroll.enabled(disabled — same) - VS Code
terminal.integrated.smoothScrolling(disabled — same) - VS Code
terminal.integrated.minimumContrastRatio(removed — same) - VS Code
terminal.integrated.scrollback(varied 1000–20000 — only changes how long duplicates persist before aging out) - VS Code
editor.accessibilitySupport: "on"(set tooff— same) - Windows Terminal
useAtlasEngine: false(same) - Terminal font (swapped to Menlo — same)
- Shell choice (zsh / bash / pwsh / cmd / Git Bash — same)
- Custom statusline (removed — same)
editorMode(vim vs normal — same)- Custom hooks (logically excluded — they fire on
Stop/Notification, but the bug appears pre-turn) - Plain
zsh(no Claude) — resize + scroll works perfectly with all the above settings unchanged
Notes for triage
The bug only manifests when Claude Code is the running process. Same terminal config + same shell with anything else (vim, less, plain zsh) behaves correctly. The leak is in Claude Code's main-screen renderer's response to redraw events (SIGWINCH, large output, recap render, prompt-state transitions) — not in the host terminal or the shell.
18 Comments
happend to me since yesterday as well
Reproducing this on v2.1.117 (one patch newer than OP) in the same VS Code integrated terminal + macOS combination. Fix is still incomplete.
Environment:
Additional trigger observed: the duplication does not require a manual SIGWINCH (resize). In my sessions it also fires after the "※ recap:" away-summary block renders, and when the input prompt transitions between states (e.g. the vim-mode
-- INSERT --indicator appearing/disappearing). Each of these events leaves a full copy of the bottom chrome (status line separators, statusLine command output, token count, input prompt) stacked in scrollback.Already ruled out on my end (matching OP's list): custom statusLine (disabling it does not help),
editorMode: "vim"vs"normal",terminal.integrated.gpuAcceleration: "off",fontLigatures.enabled: false, integerfontSize, zeroletterSpacing,awaySummaryEnabled: false.Only workaround that works:
"tui": "fullscreen"— confirming OP's finding. Default-mode renderer is still leaking frames on 2.1.117.Worth flagging: #51418 bisected this regression to v2.1.101. v2.1.100 is the last known-good version. That aligns with the Ink renderer change OP references.
Follow-up: I was able to stop the duplication on v2.1.117 in default TUI mode (no
"tui": "fullscreen") by adding"awaySummaryEnabled": falseto~/.claude/settings.json.In my case the duplication was firing specifically when the "※ recap:" away-summary block rendered after returning to the session — the recap render appears to be one of the triggers that makes the main-screen renderer leak a full frame into scrollback. Disabling the recap removes that trigger and the bug has not reappeared.
This is obviously a workaround, not a fix — the underlying renderer issue is still there and would presumably still fire on resize or other redraw events. But for anyone who can live without the away-summary feature, this is a less disruptive workaround than switching to fullscreen TUI.
I had a similar issue - closed as likely duplicate of this.
Confirming this reproduces on Linux + tmux + alacritty, v2.1.118 — so it's neither macOS-specific nor VS Code-specific; the
platform:labels undersell it.Trigger: content exceeding pane height, not resize. This matches the "large output bursts" trigger the v2.1.116 fix was meant to address — that path is still broken.
Environment
Reproducer
tmux capture-pane -p -S -50000after the response completesSignature (diagnostic): the same content block repeats at intervals that match the pane height almost exactly. In one 52-line pane I found 8 copies of
● Commit 554cea93 is in...at scrollback lines 2176, 2235, 2301, 2355, 2410, 2464, 2517, 2569 — gaps of 53–66 lines. Quick check for anyone reproducing:Any line repeating ≥4 times with spacing ≈
pane_heightis this bug.Hypothesis matching the spacing: Ink's redraw emits cursor-up + erase-line to rewind over the previous frame. When the dynamic region exceeds pane height, cursor-up saturates at the top of the viewport — it can't rewind past the top — so the portion that has already scrolled off screen is never erased. The next frame appends at the bottom and pushes exactly one pane-height of un-erased content up into scrollback. N redraws ⇒ N duplicates, spaced by pane height.
Full-height panes (88+ lines) in the same session do not duplicate, consistent with the saturation theory: if the full dynamic region fits in the viewport, cursor-up never saturates.
Does not reproduce with
tui: "fullscreen"(alt-screen avoids scrollback entirely) — matches OP's workaround.Happens in Windows, too.
At this point, I'm looking forward to what bugs Anthropic has in store for us next week.
Confirming this is not fixed in 2.1.119 and is not VS-Code-specific:
conhost.exeon the same machineWorkarounds that did not help (all tested on Windows Terminal):
"useAtlasEngine": falseinprofiles.defaults/configMatches the fullscreen-vs-inline renderer split reported in #52825 —
tui: "fullscreen"masks the symptom but sacrifices native scrollback. The v2.1.116 changelog fix for inline-mode resize duplication remains incomplete at 2.1.119.Related tracking: #52924, #52027, #52825, #52547.
i can confirm @napter 's exact issue, using 2.1.119 / tmux 3.6a / kitty
Confirming this finding from a different platform.
Linux x64 + tmux + xterm.js web client — 2.1.116's "Fixed scrollback duplication" changelog entry does not fix the variant this issue (and this report) reproduces.
I ran a deterministic harness (launch CC, 6
tmux resize-windowcalls, count duplicate UI frames in scrollback) across every native build available ondownloads.claude.aifrom 2.1.100 through 2.1.119. Result:| Version | Leak count on 6 resizes |
|---------|--------------------------|
| 2.1.100 | 0 (clean) |
| 2.1.101 | 6 (regression lands) |
| 2.1.116 | 6 (claimed fix — unchanged from 2.1.101) |
| 2.1.119 | 6 (current) |
3/3 reproducible. So the bug pre-dates 2.1.116 — the fix in that release was never applied to (or didn't cover) this variant. Bisects exactly to 2.1.101 (2026-04-10).
Posting the full bisection table + repro on the broader issue at #46834.
Consolidating thread findings and updating the issue body to reflect cross-platform scope.
Cross-platform reproductions: macOS + VS Code (original), Linux + tmux + alacritty (@napter), Linux + tmux + kitty (@igor47), Linux + tmux + xterm.js (@eyalev), Windows Terminal + conhost + gnome-terminal (@NatanaelRibF), Windows generic (@cesarvarela). Not macOS-specific, not VS Code-specific.
Regression bisected to 2.1.101 by @eyalev — last good version is 2.1.100 (2026-04-10). Leak count unchanged from 2.1.101 through 2.1.119, including 2.1.116 where the changelog claims a fix.
Triggers are broader than resize: also fires on output exceeding pane height, the
※ recap:block rendering on resume, and vim-mode indicator transitions. @napter's hypothesis — cursor-up saturating at viewport top during Ink redraws — fits the observed pane-height-spaced duplicates.Workarounds, ranked:
"tui": "fullscreen"— eliminates leak, laggier scrolling"awaySummaryEnabled": false— only fixes the recap triggerRequest: please re-triage with cross-platform scope and reopen if this was closed against the 2.1.116 fix. Issue body updated with the full details.
I tried to downgrade to 2.1.112 and it worked fine after that on my Mac.
I resize the windows and the duplication no longer happens.
I didn't need to downgrade to 2.1.100
Found a workaround in #45856, set
CLAUDE_CODE_NO_FLICKER=1in your~/.claude/settings.json:I can reproduce what looks like the same resize/reflow corruption on macOS + Ghostty with Claude Code 2.1.144.
Repro:
Observed duplicated line:
for (int j = 0; j < arr.length - 1 - i; j++) {
Environment:
Expected: resize should reflow/redraw the existing code block without adding duplicate lines.
Actual: the same code line is repeated many times after terminal resize.
Confirming this still reproduces on 2.1.154 (newest) — Windows 11 / Windows Terminal / PowerShell — and adding a render-only proof, a standalone repro, and an inline-preserving fix direction.
@napter's cursor-up-saturation theory and @eyalev's 2.1.100→2.1.119 bisection match what I see exactly. Extending the data forward and adding three things the thread doesn't have yet.
1. Still broken on 2.1.154 (Opus), Windows 11, Windows Terminal + PowerShell, inline mode. The bisection stopped at 2.1.119; it persists on the current build. The only non-fullscreen scrollback-dup fixes in the changelog are 2.1.120 ("Fixed terminal scrollback duplication in non-fullscreen mode (resize, dialog dismiss, long sessions)") and 2.1.121 ("…pressing Ctrl+L or triggering a redraw … on tmux, GNOME Terminal, Windows Terminal, and Konsole"); nothing since names the height precondition. (Consistent with your "custom statusline — same" ruling-out: I independently cleared hooks and the statusline too — it's purely the renderer.)
2. A concrete instance of your "any main-screen redraw" triggers, with no resize: a confirmation/permission dialog rendering below a tall response duplicates the response above it. Same class as your "input prompt state transitions," just a very reproducible one — painting the dialog forces a redraw while the live region exceeds the viewport, and the response stacks 3–4× in scrollback. No window move, no Ctrl+L. (I also see your resize/re-wrap variant — duplicate copies re-wrapped at different widths.)
3. Render-only proof (the model emits once): the multi-painted on-screen block maps to exactly one saved assistant message in the session
.jsonl— each unique line appears once on disk, and a scan across ~20 recent transcripts found zero duplication in saved messages. So this is purely the inline repaint, not model/transcript output. (A cheap, scriptable way to separate render-dup from content-dup during triage.)4. Standalone repro (no Claude Code) corroborating @napter's saturation theory at the escape-sequence level: a ~60-line Node script prints a frame taller than the viewport, then repaints via cursor-up (
CSI nA) + erase-line (CSI 2K). Cursor-up clamps at the viewport top — Microsoft's Console VT docs, verbatim: "Cursor movement will be bounded by the current viewport into the buffer. Scrolling (if available) will not occur." — so off-screen rows are unreachable and each redraw appends a fresh un-erased copy. Byte-level it's deterministic (N rewinds → N+1 content copies); visually it's height-gated (run in a window shorter than the frame). Happy to attach.Inline-preserving fix direction — since both listed workarounds have a real cost (downgrade loses features;
tui: fullscreenloses native scrollback): keep oversized finished output out of the redraw cycle entirely.<Static>— written to the main buffer once, never repainted — so a dialog or a re-wrap can't touch already-committed content (and it stays in native scrollback, unlike alt-screen).stdout.rowsso cursor-up can't saturate.ESC[3J("Erase Saved Lines," an xterm extension — the Windows ED docs define only params 0/1/2) from theclearTerminalpath so a full repaint can't wipe scrollback either.Just use
/tui fullscreenor setCLAUDE_CODE_NO_FLICKER=1The old renderer won't be fixed, when Anthropic itself switched to the new one completely
Nice,
/tui fullscreencompletely solved it for me. The context usage indicator disappeared, though, but the I asked Claude toand now it's very nice again.
Filed #66277 with a root-cause analysis and a self-contained repro for the resume + overflow variant of this.
In inline mode the frame buffer height is the full content height (
renderer.ts:height = altScreen ? terminalRows : yogaHeight), so committed history lives in both the repaintable frame and native scrollback at once. Any settle that grows rendered height re-runs the writer over the overflowing buffer and re-emits the row at the scrollback/viewport seam, which the terminal cannot clear from scrollback. That single mechanism seems to cover the trigger list at the top here: resize moves the seam, output bursts and recap-on-resume grow the frame, prompt-state transitions change height.The repro in #66277 strands the seam row on a freshly generated overflowing session with no recap block, on pristine 2.1.157 and 2.1.168; a tall control is clean. Notably, restoring the growing full-reset and suppressing the recap/notice both fail to fix it; only removing the overflow yields zero copies. Suggested direction: bound the live frame to the viewport and commit scrolled history to scrollback exactly once (a real
<Static>/ print-once channel), so no row exists in both.Hi all — sharing something that might help here.
Like a lot of people, the non-fullscreen renderer breaking is what finally pushed me over the edge, and like a lot of you, I refuse to switch to
NO_FLICKER=1/ fullscreen just to get clean output — losing native scrollback is a worse deal than the bug.The diagnosis in this thread is spot-on. So I took the fix it describes — emit history once, don't re-lay-out already-committed rows, redraw cleanly — and actually implemented it, by byte-patching the native binary (the app's JS is bundled inside; you can edit it in place with same-length patches and re-sign). An AI agent did most of the low-level digging.
What the patched build does, in normal (non-fullscreen) mode:
Honest scope: macOS / Apple Silicon (arm64), version-specific (done for 2.1.203 and 2.1.207). It patches a copy and installs as a separate command, so your normal
claudeis untouched. It's a hack, not an official fix, and the trade-offs are written up in the repo. Linux/Windows aren't built yet, but the same JS is inside every platform's binary, so the repo explains how you (or your own AI agent) can reproduce it on your OS and re-apply it after updates — there's a playbook and a verify harness.Repo: https://github.com/Yan-Yu-Lin/claude-code-renderpatch
If it works for you, a ⭐ on the repo helps me gauge who's finding it useful — and if it doesn't work, or you hit a snag on your platform/version, open an issue there and I'll take a look.
---
Note: this comment was drafted with Claude — English isn't my first language, so I had the AI help me put it into words. The patch and the repo are my own work.