Selecting text in the TUI corrupts multi-byte UTF-8 (Cyrillic) when copied via OSC 52
Description
When selecting non-ASCII text (Cyrillic, and likely any multi-byte UTF-8) inside the Claude Code TUI, the copy is routed through OSC 52 and the resulting clipboard content is mojibake. ASCII/Latin characters in the same selection are preserved; only multi-byte characters are corrupted.
The footer hint confirms the OSC 52 path: sent 28 chars via OSC 52 · if paste fails, hold Shift while selecting for native copy.
Steps to reproduce
- Run Claude Code in a terminal that supports OSC 52 (here: integrated terminal in VS Code, Remote-SSH).
- Have the TUI display some Cyrillic text (e.g.
Главный честный вывод вечера). - Select it with a normal mouse drag (TUI captures the selection → OSC 52).
- Paste the clipboard anywhere.
Expected
Clipboard contains the original UTF-8 text, e.g. Главный честный вывод вечера.
Actual
Clipboard contains mojibake, e.g. ÐавĐ¾Đ¹ ÑеÑÑĐ½Đ¹ Đ²ÑĐ¾Đ´ Đ²ĐµĐµÑа — the classic pattern of UTF-8 bytes encoded/decoded as a single-byte codepage. This looks like the OSC 52 base64 step is treating the string as latin1/single-byte instead of UTF-8 before base64 encoding.
Workaround (also confirms root cause)
Holding Shift while selecting (Shift+click / Shift+drag) bypasses the TUI's mouse capture and uses the terminal's native copy. The native path produces correct UTF-8. So the corruption is isolated to the TUI's OSC 52 copy path, not the terminal, OS, or locale.
Confirmed NOT the cause
- Remote locale is fine:
LANG=en_US.UTF-8,/etc/default/localeUTF-8, interactive shell UTF-8. - Native VS Code terminal copy/paste of the exact same text round-trips correctly (verified by reading the Windows clipboard byte-for-byte).
- Pasting known-good UTF-8 into the TUI renders correctly — only the OSC 52 copy direction is broken.
- Not a renderer issue (
terminal.integrated.gpuAcceleration: "off"made no difference to this path).
Suspected fix
In the OSC 52 copy implementation, base64-encode the UTF-8 bytes of the selection (e.g. Buffer.from(text, 'utf8').toString('base64')), not a latin1/binary view of the JS string.
Environment
- Claude Code: 2.1.168
- Terminal: VS Code integrated terminal, Remote-SSH
- Client OS: Windows 11
- Remote OS: Ubuntu 24.04 (noble)
- Shell: bash
This issue has 4 comments on GitHub. Read the full discussion on GitHub ↗