[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" />
This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗