[BUG] Entire transcript replays verbatim (duplicated output) after window resize — classic renderer, Windows Terminal
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code (2.1.285)
Related but distinct: #83274 reports stale content lingering after a resize.
This report is about the entire transcript being re-emitted verbatim — duplicated
output, not stale output. Same trigger, different failure mode.
What's Wrong?
After manually resizing the Windows Terminal window once during a session, the next
redraw replays the entire transcript verbatim: every previously rendered line is
written a second time, appended below the original. The result is a duplicated /
overlapping view of the whole conversation.
This is reproducible on demand, not intermittent.
Steps to Reproduce
- Windows Terminal (PowerShell profile), start
claude—tuiisdefault
(classic renderer), which is the default on Windows.
- Send a message, get a reply.
- While the second turn is streaming, drag the window edge.
- Observe: the whole scrollback — from the startup banner through the previous
turn — is emitted again, verbatim, below the original.
Expected Behavior
Repaint in place. No duplicate emission.
Evidence
- Reproduced twice; the second time deliberately, by resizing mid-turn-2.
- The duplicated block begins at the status line and ends at the previous user
message; live output continues correctly after it.
- The startup banner is partially duplicated: the
Claude Code v2.1.285and
Sonnet 5 with xhigh effort lines appear twice, but the cwd line appears once
— i.e. the boundary falls between the renderer's on-screen rows and its
recorded history.
Root Cause (from the 2.1.285 bundle)
handleResize(cols, rows) explicitly requests a full replay:
handleResize(o,l){
if(o===this.cols&&l===this.rows)return"noop";
...
if(d||l<m) // width changed, or height shrank
return this.buf+=S5+X_+TXe+ey, // clear/erase sequences
this.buf+=Ure(1,Math.max(2,p)),
this.resetTransientState(),
this.replayPending=!0, // <- schedules a full replay
this.pumpCursor=this.nativeHistory.length>0?0:-1,
this.lastFrame="",
this.commitImmediate(),
"replay";
}
nativeHistory holds everything the classic renderer has committed to the
terminal's native scrollback. tickPump() then re-emits it from index 0.
The intent is "clear the screen, repaint at the new width". On Windows Terminal
this fails: the erase sequences are addressed to the renderer's accounted cursor
position (committedTop / pumpCursor), but Windows Terminal has already reflowed
the scrollback on resize, so the real cursor no longer matches. The erase lands in
the wrong place and the replayed content is appended instead of replacing the
original — hence verbatim duplication rather than a clean repaint.
Consistent with the Windows Terminal maintainer's assessment that resize issues
stem from applications' redraw handling (microsoft/terminal#14448).
Workaround
/tui fullscreen— the alt-screen renderer does not maintainnativeHistory
and does not go through this path. Verified: the duplication is gone. Side
effect: the static Clawd banner art is not drawn.
- With the classic renderer: avoid resizing the window mid-session. Sizing the
window before starting avoids the trigger entirely.
Not a workaround
- Ctrl+L does nothing. In the
Chatcontext,ctrl+lis bound to
chat:clearInput, and chat:clearScreen maps to the same handler. forceRedraw()
is only invoked internally (resize / stdout backpressure / programmatic prompt
change) — the classic renderer has no user-reachable full-repaint keybinding.
Environment
- Claude Code: 2.1.285
- OS: Windows 11 Home China, 10.0.26200
- Terminal: Windows Terminal (1.24.11911.0; 1.21.10351.0 also installed)
- Shell: PowerShell 5.1.26100.9278 (profile); also observed under pwsh 7.6.6
tui: default (classic renderer)- Terminal captured at 80x24
3 Comments
I can reproduce on MacOS ZSH. Latest claude code version as we speak and it keeps happening with or without terminal resizing. I believe it happens when claude code is outputting while offscreen.
It's so annoying and the duplication happens even in numbered lists. For example, if there's an expected output like this:
Claude would turn it into a longer duplicate list:
Fix it y'all.
Same bug here, on a newer build and a slightly different setup, so adding data.
tui=default(classic renderer)What I see: not the whole transcript (as in the report above), but repeated fragments. The same sentence of the answer shows up 4-5 times with tool output between the copies, my own prompt line appears twice, and a cut-off tail of the previous reply ("it.") is left stranded. The conversation itself is fine, only the screen is.
My guess, not verified: after the re-wrap the live area is taller than the window, rows that have gone into scrollback can't be erased, so each redraw leaves another copy. A burst of resize events (multi-monitor drag) multiplies it.
Workaround:
/tui fullscreenavoids it./clearorclaude --continuecleans the screen but not the scrollback.Reproducing the same behavior on WSL2 + Windows Terminal:
Environment
TERM=xterm-256colorSymptom
Resizing the window during an interactive session causes past conversation history to be re-emitted into scrollback as duplicated/ghost frames — the transcript appears doubled (or more, one copy per redraw during the resize drag). Conversation state itself is unaffected; it's scrollback pollution only.
Partial mitigations observed
Ctrl+Lrepaints the live viewport and fixes visible corruption, but the ghost frames already pushed to scrollback remain.Ctrl+L, rendering width is sometimes still stale until the next keystroke (similar to #80123).claude --resumeis the only way to get a clean scrollback.Happy to provide more detail if useful.