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

Resolved 💬 5 comments Opened May 14, 2026 by vbogdanmg 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 ↗

This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗