[BUG] Main-screen input renderer emits a stray backspace before the first keystroke after ~4s idle, corrupting the prompt (Windows/Cygwin, mintty/tmux)

Status Open
Maintainer reply None cached
Activity 1 comment · opened Jul 18, 2026

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?

On the main screen, Claude Code's input renderer emits a literal backspace (0x08) immediately before the first character typed after roughly 4 seconds of input idleness. That single byte fully accounts for the corruption. The character lands one column left of where it belongs, on top of the prompt's non-breaking-space pad, so typing an A renders as >A instead of > A. The input buffer is always correct, so this is display-only.

Three properties make it easy to confirm and easy to miss:

  • Triggered by an idle gap. Below about a 4 second gap it never happens. Above about 4.5 seconds it always happens.
  • Recurs for the whole session. Any keystroke that follows an idle gap gets the backspace, for the life of the session. A keystroke typed immediately after another does not. This is why it shows constantly in normal use: every wait for a model response is well past the threshold.
  • Only on the main screen. Environments that put Claude on the alternate screen (VS Code's integrated terminal) are clean. Environments that leave it on the main screen (mintty, and tmux anywhere) corrupt the pad. Same shell, same TERM, same Windows node build across both.

CLAUDE_CODE_ALT_SCREEN_FULL_REPAINT=1 avoids it by forcing the full-repaint path everywhere.

What Should Happen?

Expected: the character appears after the prompt's pad, as > A.
Actual: the character overwrites the pad, rendering as >A. The buffer is unaffected, so submitting works normally.

Steps to Reproduce

  1. From a Cygwin shell (mintty, with or without tmux), start Claude Code.
  2. Wait for the input box to appear, then wait at least 5 more seconds without typing. No message needs to be submitted.
  3. Type a single character.

The idle wait in step 2 is load-bearing. Typing within about 4 seconds of the box appearing, or of your last keystroke, does not reproduce this at all. Type promptly and you will see correct output and conclude the bug is absent. Wait 5 seconds and it is completely reliable.

Claude Code Version

v2.1.212, run via npx --yes @anthropic-ai/claude-code@latest

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

Other: Cygwin mintty, reproduced both with tmux 3.2 and with no tmux at all. Clean in the VS Code integrated terminal (xterm.js) on the same Cygwin bash.

Is this a regression?

I don't know

Additional Information

Environment
  • Claude Code v2.1.212, run via npx --yes @anthropic-ai/claude-code@latest
  • Windows 10 Pro
  • Cygwin 3.6.x, Windows node v24.x (process.platform reports win32)
  • Reproduced under tmux 3.2 and under bare mintty with no tmux running at all
  • Reproduced under both TERM=screen-256color and TERM=xterm-256color
  • Clean in the VS Code integrated terminal (xterm.js), on the same Cygwin bash and the same TERM=xterm-256color
Which renderer is at fault

The environments that render correctly and the ones that corrupt the pad are not running the same renderer, and the difference is observable with no byte capture at all. Launch Claude, exit it, and watch what happens to whatever was on screen beforehand:

| Environment | On exit | Screen buffer | Result |
|---|---|---|---|
| VS Code integrated terminal | prior screen content restored intact | alternate | correct |
| mintty | prior content cleared, screen left blank | main | backspace bug |
| tmux (in mintty or in VS Code) | prior content cleared | main | backspace bug |

Restoring the pre-launch screen on exit is the alternate-screen signature (the behaviour of vim, less, and htop). No capture from any broken environment contains ESC[?1049h, ESC[?1049l, or ESC[?47h. mintty, tmux, and a ConPTY harness all stay on the main screen. This matches the name of the workaround, CLAUDE_CODE_ALT_SCREEN_FULL_REPAINT. Forcing it gives the main-screen environments the full-repaint path, and the backspace disappears.

So the defect appears to live specifically in the main-screen incremental renderer, which VS Code never selects. Note that tmux inside the VS Code terminal is also broken, so the outer terminal is not what matters. What matters is the terminal Claude talks to directly. The open mystery is what decides between the two renderers: the clean alternate-screen path exists and forcing it fixes everything, but we could not select it from outside real VS Code by any input we controlled (details in the collapsed section below).

Byte-level evidence

Raw output was captured three independent ways: tmux pipe-pane under tmux, mintty --log in a bare mintty with no tmux, and a node-pty ConPTY harness. All record the exact bytes the program writes.

1. The backspace. Everything emitted for one keystroke into an idle box under tmux:

0f  1b5b3c75  1b5b3e3175  08  41   1b5b4b
SI  ESC[<u    ESC[>1u     BS  'A'  ESC[K

0x08 is a literal backspace. Captured on three separate runs (08 41, 08 5a, 08 51 for A, Z, and Q).

In a bare mintty with no tmux server ($TMUX/$TMUX_PANE unset), one keystroke produced 25 bytes, and a byte-aligned scan of the whole log finds exactly one 0x08, immediately before the character:

1b5b3f3235 68  0f  1b5b3f32303236 68  1b5b3f323032366c  08  41
ESC[?25h       SI  ESC[?2026h         ESC[?2026l        BS  'A'

2. Claude's own output stream contradicts itself inside one burst. This is the strongest single point. The same burst that backspaces the character to column 2 ends by parking the cursor at column 4:

08 51  ...  1b5b32313b3448  1b5b3f323568
BS 'Q' ...  ESC[21;4H       ESC[?25h

ESC[21;4H (column 4) is only correct if Q had been written at column 3, but the backspace put it at column 2. Both bytes are emitted by Claude, one after the other in the same burst. The two positions cannot both be right, and because the contradiction is internal to Claude's output stream, no terminal quirk can explain it.

3. The redraw parks the cursor at column 3, so the backspace is wrong unconditionally. The full post-submit redraw's last cursor-position sequence is ESC[21;3H. Column 3 is correct for an empty box (> at column 1, pad at column 2, cursor at column 3). From column 3 the correct next action is to write the character. The typing path instead backspaces first, which only makes sense from column 4.

4. The terminal executes the backspace exactly per spec (no Claude involved). Replaying the byte shape from a bare bash prompt, same tmux pane, same Cygwin:

| Command | Bytes | Renders |
|---|---|---|
| printf ">\302\240\010A" | > nbsp BS A | >A (reproduces the symptom) |
| printf ">\302\240A" | > nbsp A | > A (healthy) |

The corruption is fully accounted for by that one byte, and any conformant terminal produces the same overwrite. The terminal is not at fault.

<details>
<summary><strong>Additional evidence and things ruled out</strong></summary>

Ruled out: other programs on the same machine

No other program on the same machine does this, including a React/Ink app. Same Cygwin, same tmux pane, same Windows node build, same idle gaps that make Claude Code backspace every time:

| Program | Idle gaps tested | 0x08 |
|---|---|---|
| bash readline | 6s, 8s, 30s (n=3) | 0 |
| vim, insert mode | 6s, 8s, 10s, 30s (n=4) | 0 |
| Ink 7.1.1 app (React TUI on the same node) | 5s, 8s, 10s, 30s (n=4) | 0 |
| Claude Code | 4.5s to 30s (n=12) | 1 every time |

The Ink comparison is the pointed one, since it is a React terminal app rendering a > + nbsp + text prompt on the identical runtime. After a 30s idle it emits ESC[?2026h ESC[23;1H 3e c2 a0 41 (absolute CSI positioning, pad written literally, no backspace), the same shape as Claude Code's own full-repaint path. vim redraws the whole line instead, also with no backspace. One honest limit: this Ink app does not enable the kitty keyboard protocol or whatever incremental cursor-diffing Claude Code uses, so it shows that a standard Ink app on this platform is clean, not that Ink can never produce this.

The idle threshold, measured

14 fresh sessions, each verified to start from a clean shell, varying only the idle delay before a single keystroke, two reps per delay:

| Idle delay | 0x08 (both reps) |
|---|---|
| 0.2s, 1s, 2s, 3s, 3.5s, 4s | 0 |
| 4.5s, 5s, 8s, 30s | 1 |

The transition sits between 4.0s and 4.5s, with no flakiness at any delay.

Recurring within a session

Type A after 8s idle, B 0.3s later, C after 8s more idle. Two sessions, identical:

| Keystroke | Idle before it | 0x08 |
|---|---|---|
| A | 8s | 1 |
| B | 0.3s | 0 |
| C | 8s | 1 |

B emits a single raw byte with no positioning. C takes the backspace again after the gap.

The env var is the only variable that matters

All on v2.1.212, byte-aligned 0x08 counts:

| Context | CLAUDE_CODE_ALT_SCREEN_FULL_REPAINT | 0x08 | Result |
|---|---|---|---|
| tmux 3.2 | unset | 1 | >A, broken |
| tmux 3.2 | 1 | 0 | > A, correct |
| bare mintty, no tmux | unset | 1 | broken |
| bare mintty, no tmux | 1 | 0 | correct |

Ruled out: platform and TERM

Linux does not reproduce it. Tested in a Linux container (node:22-slim, tmux 3.3a) with an authenticated session. Claude positions with CSI sequences to column 3 and emits no backspaces.

TERM is not the variable either. Cygwin breaks under both screen-256color and xterm-256color. Linux is clean under tmux-256color and screen-256color.

Ruled out: the kitty-protocol correlation

In our first 26 trials the 0x08 was present in exactly those bursts that also carried a SI (0x0f) plus kitty keyboard protocol push/pop (ESC[<u, ESC[>1u) prefix, and absent otherwise, 26/26. That looked causal. It is not: running with TERM_PROGRAM=vscode set suppresses the kitty prefix while the backspace remains (n=4). So the prefix is not necessary for the backspace, and the agreement held only because those 26 trials shared one environment. We report the correlation because the prefix may still point at the code path, not as evidence of the mechanism.

Ruled out: what selects the renderer

We could not reproduce the clean alternate-screen path anywhere except real VS Code, despite matching its inputs closely:

  • A node-pty ConPTY harness (VS Code's own pty mechanism) with TERM_PROGRAM=vscode, COLORTERM=truecolor, and the VS Code identity vars set: still main screen, still 0x08.
  • The same harness with a real @xterm/headless terminal attached and its replies wired back to the pty, so capability queries were actually answered: still main screen, still 0x08. (xterm.js in fact sent zero replies to Claude's ESC[>0q and ESC]11;? queries, so answering-versus-not is not the discriminator either.)
  • The same harness spawning through Cygwin bash --login -i rather than npx.cmd directly, to match VS Code's real process chain: byte-identical result.

So whatever selects the alternate screen in the real VS Code terminal, we could not trigger it from outside, and it is not the shell, TERM, TERM_PROGRAM, COLORTERM, the pty type, or the terminal answering queries.

</details>

Workaround

CLAUDE_CODE_ALT_SCREEN_FULL_REPAINT=1 eliminates the backspace: with it set, the byte stream contains zero 0x08 and the line renders correctly. The cost is a full repaint every frame, which is visible as the cursor briefly jumping around the screen.

Prior art (issue tracker search)

We searched the tracker before drafting and found no issue describing this specific symptom (a stray 0x08 before the first keystroke after an idle gap, jamming the character onto the prompt pad on the main-screen input box). The closest existing reports are different faults:

  • #14562 (open) corrupted first character in Windows Terminal, but a glyph substitution (]Work for > Work), not a one-column pad overwrite, and a v2.0.73 regression.
  • #42468 (closed as duplicate) cursor renders a full row below the > prompt, in tmux + iTerm2 on Linux. Wrong axis and wrong platform.
  • #29937 general tmux text overlap/overwrite corruption, not the input line specifically.
  • #33048 the ~30s idle "waiting for your input" notification corrupting screen/tmux. Shares the idle-timer angle, different surface and mechanism.

Related but not a duplicate: the official fullscreen docs (code.claude.com/docs/en/fullscreen) describe CLAUDE_CODE_ALT_SCREEN_FULL_REPAINT for the fullscreen renderer, noting that the incremental path "sends only the cells that changed" and that "ConPTY-backed hosts coalesce these positioned writes incorrectly." That is the same class of defect, but documented only for fullscreen mode. The manifestation reported here is on the ordinary main-screen input box, which the docs do not cover.

Search caveat: we cannot prove exhaustiveness. The repo has a very large issue count and our queries were English and symptom-based, so a differently-worded report could exist.

Not tested
  • Windows outside Cygwin (Git Bash, MSYS2, WSL). This report claims Windows/Cygwin only, not "all Windows".
  • Native Windows terminals other than VS Code (Windows Terminal is reported clean by the user but we did not byte-capture it).
Open questions
  • Why the main-screen path emits a backspace at all, given its own redraw leaves the cursor at column 3, from which writing the character directly would be correct.
  • What runs at the ~4 second idle mark that re-arms this path.

We have not looked at the source and are not asserting an internal cause. The above is observed byte-level behaviour.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗