[BUG] Terminal charset corruption (G1 alternate set stuck) after interrupted spinner / escape sequence
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:
- Connect to a Linux pod via a remote-control overlay (RDP / TeamViewer / similar)
running a Windows-side terminal (Windows Terminal in my case).
- SSH from the Windows host into the Linux pod.
- Launch
claude(Claude Code TUI). - Run a long task that emits spinner / progress / monitor events.
- 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).
- 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 matching0x0F(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" />
5 Comments
Reproducing with a much simpler setup — Claude Code running natively on Windows, no SSH, no remote pod, no RDP/TeamViewer:
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" />
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
$TERM: xterm-256color.claude/hooks or statusline customizationsSymptom 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:
logger→koggerPOST→hOSTfinishing→kinishingcaptureMessage→captureTessageexporter→ixporterSame diagnostic signals as the original report
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[0mon 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" />
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" />
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:
Then pin it so the auto-updater doesn't silently bump you back:
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:
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:
Rolled back to 2.1.140 again — still the only clean version.
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.