Renderer corrupts screen in long iTerm2 sessions — CLI emits cursor-up sequences far larger than the viewport, repaint anchors to row 1 (regression after 2.1.162, still present in 2.1.177)
Summary
In long-running / resumed sessions on macOS iTerm2, the TUI renderer progressively corrupts the screen: the prompt jumps to the top of the viewport and stale content below is slowly overwritten on subsequent repaints. A full redraw (Ctrl+L) recovers temporarily, then it recurs. Short / fresh sessions are unaffected.
Root cause is captured below from a raw script tty log: the CLI itself emits cursor-up escape sequences far larger than the terminal height (up to ESC[712A), which clamp at the top of the screen and cause the next repaint to start at row 1. The capture is forensically dispositive and I can attach it.
Environment
- Claude Code versions:
- Clean: 2.1.140 (long historical use), 2.1.162 (real-world use, no corruption observed over a full working day).
- Corrupting: 2.1.170 and 2.1.173 (forensic capture below), and 2.1.177 (a live session running 2.1.177 reproduced the corruption; not separately captured).
- 2.1.169: ambiguous, not conclusively classified.
- So the regression was introduced somewhere in 2.1.163–2.1.170 and persists through the latest build (2.1.177). The exact introducing build is not yet bisected.
- OS: macOS (Darwin 25.4.0)
- Terminal: iTerm2 3.6.9
- Renderer: default TUI renderer (
tui: defaultin settings, which uses the terminal's alternate screen buffer) TERM=xterm-256color, no tmux- Aggravators present in this setup (not confirmed as causes): long resumed sessions, a custom statusline, and the remote-control footer (a persistent footer line in the TUI)
Root cause (from raw tty capture)
I captured the renderer output with script while corruption was occurring. The CLI emits cursor-up escape sequences far larger than the terminal can hold:
ESC[<N>Awith N ranging from 101 up to 712.- 3918 such oversized moves in a single capture, out of 14843 cursor-up moves total.
- For reference, the largest cursor-up observed in a clean (non-corrupting) session is 59 rows. Any move past the terminal height is illegitimate: the terminal clamps the cursor at row 1 (it cannot scroll above the top of the screen), so the subsequent repaint begins at row 1 and overwrites on-screen content.
- Also observed: width desync — the renderer paints at a stale, narrower width (text breaks one word per line), suggesting the renderer's internal column/row model has drifted from the terminal's actual size.
This is consistent with the renderer tracking a growing assistant response as its repaint frame, computing a cursor-up larger than the physical screen, and anchoring the repaint to the top instead of the correct row.
Anyone can reproduce the analysis on the attached capture with:
perl -ne 'while(/\e\[(\d+)A/g){$t++; $b++ if $1>=100} END{printf "%d cursor-up total, %d exceed 100 rows\n",$t,$b}' capture.log
Steps to reproduce
- Resume a long session in iTerm2 on 2.1.170+ (default TUI renderer).
- Use it through several streamed responses. A monitor resize / display change while a response is rendering appears to trigger onset.
- The screen begins jumping to the top with stale text overwritten below.
Reproduction caveat: a fresh session reproduces poorly. We were unable to reproduce with any zero-token synthetic trigger on a known-bad build — idle resize storms, paste storms, transcript-viewer scrolling, and bash-mode local streaming, each combined with window resizes, in both detached ptys and a real iTerm2 window. All stayed clean (max cursor-up 59, i.e. correct). Reproduction appears to require real model streaming (a growing assistant message) plus accumulated long-session renderer state.
Not terminal-specific
This was only observed in iTerm2, but the captured sequences (ESC[712A) would corrupt any terminal that clamps cursor-up at row 1, which is standard VT behavior. The fault is in the emitted sequences, not in iTerm2's handling. Other terminals (Terminal.app, kitty) were not tested.
Workarounds tried
CLAUDE_CODE_FORCE_SYNC_OUTPUT=1— insufficient, recurs.- Remote control off — insufficient, recurs.
- Pin to a pre-regression build (2.1.140, or 2.1.162) — resolves it.
Impact
Sessions become unusable without repeated Ctrl+L. The only reliable fix is to downgrade and pin to an old build, which blocks adoption of current releases.
I have the raw script capture with the corruption in the act (≈1.9 MB) and can attach it on request.
This issue has 6 comments on GitHub. Read the full discussion on GitHub ↗