[BUG] Terminal charset corruption (G1 alternate set stuck) after interrupted spinner / escape sequence

Status Fixed / completed
Reported on v2.1.141
Maintainer reply None cached
Activity 5 comments · opened May 14, 2026 · closed May 22, 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?

Running Claude Code in a Linux pod accessed through a Windows-side terminal
(Windows Terminal → RDP / TeamViewer → SSH → Linux pod), the entire CLI display
occasionally switches into the terminal's G1 alternate character set mid-stream.
All subsequent text gets remapped through the alternate glyph table, leaving the UI
unreadable (e.g. normal English text renders as ShÌtÉ$ÌÑÔSŠh n©ÑÌSÔ Š©ÔbSŠÉ).

Lines that emit their own charset-reset escape (such as completed task-list
checkmarks ) still render correctly while the rest of the screen stays
corrupted — which confirms the issue is sticky terminal state, not encoding
loss in the bytes themselves.

The session and conversation context are unaffected; only the rendering is broken.
Recovery requires sending a charset-reset escape sequence to the TTY:
printf '\e(B\017\e[0m\ec' > /dev/tty

What Should Happen?

The CLI should defensively restore the terminal's character set (G0 = US-ASCII,
Shift In active) on:

  • spinner-frame cleanup,
  • signal-handler exits (SIGINT, SIGTERM),
  • monitor / task-output rendering boundaries.

So that even if a spinner or status line is interrupted mid-render, the terminal
is never left with the alternate (G1) charset armed.

Error Messages/Logs

(no error logs — the CLI keeps running; only the rendering is corrupted)

Steps to Reproduce

Intermittent — observed ~once per several-hour session, hard to deterministically
trigger but reliably present when these conditions are met:

  1. Connect to a Linux pod via a remote-control overlay (RDP / TeamViewer / similar)

running a Windows-side terminal (Windows Terminal in my case).

  1. SSH from the Windows host into the Linux pod.
  2. Launch claude (Claude Code TUI).
  3. Run a long task that emits spinner / progress / monitor events.
  4. Interrupt or trigger an event-burst mid-spinner-frame (Ctrl-C on a sub-task,

a Monitor task firing while another LLM call is rendering, window resize during
spinner).

  1. Subsequent rendering switches to alternate charset; text becomes unreadable.

Workaround (does not require exiting Claude Code):
printf '\e(B\017\e[0m\ec' > /dev/tty

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.141 (Claude Code)

Platform

Anthropic API

Operating System

Ubuntu/Debian Linux

Terminal/Shell

Xterm

Additional Information

## Root cause hypothesis

Claude Code emits Unicode glyphs in its UI (em-dashes, bullets, checkmarks,
spinner frames, status-bar borders). When a spinner frame or status line is
interrupted before its cleanup escape is written, the byte stream feeding the
terminal can contain either:

  • A stray 0x0E (Shift Out) without a matching 0x0F (Shift In), or
  • An interrupted ESC ( <charset> G0-designation sequence that the terminal

parsed but couldn't complete.

The terminal stays in alternate (G1) charset mode and corrupts all subsequent
rendering until something switches it back.

ConPTY (Windows pseudo-terminal layer) and remote-control overlays exacerbate
this by occasionally dropping or batching control bytes.

## Related prior art (same class, different escape protocol)

  • #38672 / #38829 — Kitty keyboard protocol (KKP) not reset on exit causing

similar TUI state-leak corruption (different escape family, same root pattern:

  • #33048 — idle notification corrupts terminal in screen/tmux (similar:

emission leaves state corrupted).

## Suggested fix

In the CLI's signal handler (SIGINT / SIGTERM) and spinner-cleanup paths, emit
\017\e[0m (Shift In + SGR reset) on every exit path. Optionally prefix every
TUI rendering line with \017 defensively when running in non-tmux/screen
environments. This is the same class of fix Anthropic shipped for #38672 (KKP
state reset on exit) but for the ECMA-48 G0/G1 charset designation protocol.

## Screenshot

(Attach the claude_cli.jpg screenshot showing the garbled display — the bottom
4 task-list lines render fine because each line emits its own charset-reset
escape, while the rest of the screen stays in alternate charset.)

<img width="3067" height="1093" alt="Image" src="https://github.com/user-attachments/assets/930b42ba-694a-45f7-bf69-c3e2e900df7a" />

View original on GitHub ↗

5 Comments

KamilDev · 3 months ago

Reproducing with a much simpler setup — Claude Code running natively on Windows, no SSH, no remote pod, no RDP/TeamViewer:

  • Windows 11
  • VS Code integrated terminal (ConPTY)
  • PowerShell 7.6.1
  • Claude Code 2.1.141

Likely a regression in 2.1.141 — first hit it today, yesterday on 2.1.140 was fine. 2.1.141 shipped 2026-05-13 ~23:19 UTC and this issue was filed ~3 hours later, which lines up.

Same selective corruption — ASCII-only lines and lines that emit their own reset (the "almost done thinking..." spinner text, numbers, 244 px) render fine while the rest of the screen is remapped through the alternate charset. Screenshot attached.

Extra data point: resizing the terminal a few columns fixes the rendering temporarily (presumably the re-layout emits a full clear), but it can come back later in the same session.

Since there's no SSH or remote-control layer here, the bad bytes have to be coming from Claude Code itself — not from intermediate transports mangling the stream.

<img width="1272" height="1919" alt="Image" src="https://github.com/user-attachments/assets/b4b193f0-77bf-41b9-96fa-c9d94a144bb3" />

edwrdcrpio · 3 months ago

Hitting what looks like the same root cause on a different platform/terminal combo — adding here rather than filing a duplicate, since it strengthens the "stuck terminal state" diagnosis.

Environment

  • Claude Code: 2.1.141
  • Terminal: VS Code integrated terminal (xterm.js), not a native terminal
  • OS: macOS (Darwin 24.6.0), MacBook Air M4
  • $TERM: xterm-256color
  • No project-level .claude/ hooks or statusline customizations

Symptom variant
Instead of G1 alternate charset, the terminal renders text with combining diacritical marks (mostly combining dot above, U+0307) overlaid on letters, with the base letter sometimes replaced. Examples from one session:

  • loggerkogger
  • POSThOST
  • finishingkinishing
  • captureMessagecaptureTessage
  • exporterixporter

Same diagnostic signals as the original report

  • Session rendered cleanly for ~30 minutes, then degraded and stayed degraded
  • Affects all output sources after onset (tool results, assistant text, spinner) — not just one tool's output
  • Underlying conversation/state intact — corruption is purely render-layer
  • Highlighting text with the cursor to copy actively changes which characters are corrupted in real time — strong signal the cell buffer is being re-rendered with non-deterministic glyph placement on each repaint
  • Session involved long streaming outputs (curl piped to python printing Sentry event payloads), consistent with the "interrupted spinner during event burst" trigger hypothesis

Why this matters for the fix
Suggests the underlying class is broader than "G1 charset stuck" — any terminal state that's mode-sensitive (alternate charsets, combining-mark composition modes in xterm.js, etc.) can get stuck the same way if Claude Code's TUI doesn't defensively reset state on spinner-cleanup and signal-handler paths. The proposed fix (emit \017\e[0m on every exit/cleanup path) would address both variants.

<img width="1412" height="318" alt="Image" src="https://github.com/user-attachments/assets/2a16e7ef-38d2-4ad2-af2a-0f05301c2bd4" />

ChazUK · 3 months ago

I am getting the same in Windsurf, it is corrupting all my other terminal windows.

<img width="880" height="385" alt="Image" src="https://github.com/user-attachments/assets/1030e317-a9cd-429b-a81d-8c19b0e90a9d" />
<img width="848" height="417" alt="Image" src="https://github.com/user-attachments/assets/9dc49741-82ea-4ec0-838b-f63ebaf65922" />

KamilDev · 3 months ago

Confirming the regression range and a working downgrade path.

I was hitting this consistently on 2.1.143 (Windows 11, VS Code integrated terminal, pwsh 7.6.1, ConPTY) — no improvement on 2.1.141 → 2.1.142 → 2.1.143.

Downgrading to 2.1.140 stops the corruption entirely. The native installer has a built-in version subcommand:

claude install 2.1.140 --force

Then pin it so the auto-updater doesn't silently bump you back:

// ~/.claude/settings.json
{
  "env": {
    "DISABLE_UPDATES": "1",
    "DISABLE_AUTOUPDATER": "1"
  }
}

Been running on 2.1.140 for a while now — zero corruption events. So the affected range is 2.1.141 → 2.1.143 inclusive (every release since this issue was filed).

Two 2.1.141 changelog entries touch the rendering area and look like reasonable starting points for the diff:

Improved spinner feedback during long thinking periods — the spinner now warms to amber after 10 seconds to signal Claude is still working
Fixed multi-line statusline output dropping or corrupting rows when any line exceeds terminal width

Pinning to 2.1.140 in the meantime.

---

Update (2026-05-20): still reproduces on 2.1.145, same setup. 2.1.145 carries the 2.1.144 terminal-rendering fixes, so those do not address this:

Fixed garbled terminal output after a missed window-resize event (e.g. dragging a VS Code split-pane divider) — now self-heals on the next frame instead of requiring Ctrl+L
Fixed progressive terminal display corruption (stale/garbled glyphs) that could appear in very long sessions and only cleared on terminal resize or restart

Rolled back to 2.1.140 again — still the only clean version.

github-actions[bot] · 1 month ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.