/copy writes the clipboard as latin-1, so non-ASCII output pastes as mojibake (still broken in 2.1.215)
Summary
/copy writes the clipboard as latin-1, so any non-ASCII output pastes as mojibake. Still broken in 2.1.215. The dump file /copy writes to /tmp/claude-*/response.md is clean UTF-8, and pbcopy < that_same_file produces a correct clipboard, so the corruption is in the clipboard write and not in the source text. I confirmed the exact transformation rather than guessing at it (details below).
This was reported before in #66065 and #66421. #66065 was closed by the inactivity bot with "please open a new issue if this is still relevant", and #66421 was auto-closed as a duplicate of it. Neither was fixed, so filing fresh per that message.
Measured root cause
The clipboard write takes UTF-8 bytes and treats them as latin-1. I predicted the corrupted size from the clean file before measuring it:
raw = open('/tmp/claude-501/response.md','rb').read() # what /copy itself dumped
len(raw) # 2372, valid UTF-8
# hypothesis: those UTF-8 bytes get decoded as latin-1, then re-encoded as UTF-8
len(raw.decode('latin-1').encode('utf-8')) # 4109
Measured clipboard via pbpaste | wc -c: 4109 bytes. Predicted: 4109 bytes. Exact match, so the transformation is utf-8 bytes -> decode latin-1 -> encode utf-8. Not a font or rendering issue.
The paste agrees: 好了,给你两条路 arrives as 好äºï¼ç»ä½ 两æ¡è·¯, which is E5 A5 BD (好) read as three separate latin-1 characters. pbpaste | file - on the bad clipboard also reports NEL line terminators, which is 0x85 from the same mangling.
Possible common factor: VS Code / Cursor integrated terminals
I went back through the earlier reports and the terminal is the thing they share, which may be more useful than the OS:
| Issue | Environment |
|---|---|
| #66065 | VS Code, devcontainer |
| #72731 | Cursor integrated terminal, SSH to Debian |
| #73284 | Cursor integrated terminal |
| this one | VS Code-family integrated terminal (TERM_PROGRAM=vscode), macOS, local, no SSH or container |
Mine is the local macOS case with pbcopy available on PATH and still broken, which rules out the "xclip invoked without a UTF8_STRING target" explanation that fits the Linux reports. #66098 separately points at OSC 52 for a different copy path.
To be clear about what is measured and what is not: the byte-level mechanism above is measured. The guess that the integrated-terminal clipboard path (likely OSC 52 rather than pbcopy) is the one being chosen and mangled is a hypothesis from the correlation, not something I verified. I only have the one terminal to test in.
Reproduction
- macOS, Claude Code 2.1.215, VS Code-family integrated terminal
- Get any assistant output containing non-ASCII (CJK, Cyrillic, accented Latin, em dash, emoji)
- Run
/copy - Compare
pbpaste | wc -cagainstwc -c /tmp/claude-*/response.md
The clipboard comes out larger than the file it was built from, and pasting anywhere shows mojibake. ASCII-only output is fine.
Workaround, which is also what isolates it:
pbcopy < /tmp/claude-501/response.md # clipboard now byte-identical to the file
Expected
Clipboard bytes identical to the dump file that /copy already writes correctly.
Proposed fix
Write the clipboard from the same UTF-8 bytes used for the dump file, instead of letting the text go through a latin-1 or default single-byte encode on the way to the clipboard call. Since the dump file is already correct, the encoding is being dropped at the handoff.
Cheap regression test: assert clipboard_bytes == dumpfile_bytes for a string with at least one character above U+007F.
Related
- #66065 same
/copybug, closed by the inactivity bot rather than fixed - #66421 same bug, auto-closed as a duplicate of #66065
- #72731, #73284 open, Cursor terminal, same encoding family
- #66098 OSC 52 path specifically
- #30865, #42417 older Windows variants
Environment
- Claude Code 2.1.215
- macOS 26.5.2 (build 25F84), arm64
TERM_PROGRAM=vscode,TERM_PROGRAM_VERSION=3.11.13,TERM=xterm-256colorLANG=en_US.UTF-8pbcopy/pbpastepresent on PATH- No SSH, no container, no WSL
---
I hit this in normal use, measured it, and drafted the writeup with Claude Code, then reviewed and edited it before filing.
Showing cached comments. Read the full discussion on GitHub ↗
3 Comments
Update: I have a deterministic repro now. It is not intermittent, it needs two conditions at once, which I think explains why the earlier reports on this disagree with each other.
It breaks only when the fullscreen renderer is active AND the copied text contains box-drawing / symbol characters (U+2500 range, U+2605). Either one alone is fine.
| | text has box-drawing / ★ | text has none |
|---|---|---|
|
"tui": "fullscreen"| BROKEN (2 for 2) | OK ||
"tui": "default"| OK | OK |Every run measured the same way:
/copywrites a dump file, then comparepbpaste | wc -cagainstwc -con that file, immediately, before anything else touches the clipboard.Both broken runs land exactly on
len(raw.decode('latin-1').encode('utf-8')), so the corruption is the same latin-1 round trip described in the original report. The dump file is clean UTF-8 in every case, including the broken ones, so only the clipboard write is affected.Length is not the variable. The longest sample (2899 bytes) was the one that came out clean; it just had no box-drawing characters in it.
What I could not separate: both broken samples contained U+2500-range box-drawing and U+2605 together, so I cannot say which of the two triggers it, or whether it is the whole ambiguous-width class. The broken sample had 174 box-drawing characters and 6 symbols. Em dash (U+2014) appears in a clean sample, so that one is not enough on its own.
Guessing at the mechanism, and this part is a guess: the fullscreen renderer has to compute display width for every character itself, where the default renderer leaves that to the terminal. Ambiguous-width characters are exactly the ones that path has to make a call on, so a bug there could corrupt the buffer that later feeds the clipboard while the on-screen rendering still looks correct. That matches what I see, since the text displays fine and only the copy is wrong.
If that is right, this and #66269 are the same bug seen from two sides. #66269 reported the renderer as the cause and found
"tui": "default"fixes it; other reporters on fullscreen presumably were copying text without those characters and saw nothing wrong. The interaction would explain both.Environment unchanged from the original report: Claude Code 2.1.215, macOS 26.5.2 arm64,
TERM_PROGRAM=vscode,LANG=en_US.UTF-8.Repro, if useful:
/tui fullscreen─) plus CJK or any non-ASCII/copypbpaste | wc -cvswc -c /tmp/claude-*/response.md, they differ, and the clipboard size equals the latin-1 round trip of the file/tui defaultand repeat the same steps, sizes now matchCould not reproduce on v2.1.233 (macOS 26, arm64) in iTerm2 and in tmux inside iTerm2, with the fullscreen renderer on and text containing CJK + a run of
─box-drawing +★.Steps:
claudewith/tui fullscreen, ask for a reply containing好了,给你两条路 ★ ─────────── café — résumé./copy.pbpaste | wc -cwithwc -c /tmp/claude-*/response.md.Observed: both 81 bytes,
cmpreports the clipboard and the dump file identical, paste is correct.Expected (per the report): clipboard larger than the file, latin-1 mojibake on paste.
Assessment: this looks like a genuine bug, but with two halves. The byte pattern you measured (each UTF-8 byte re-encoded as one Latin-1 character) is exactly what a known bug in the terminal-side OSC 52 clipboard handler shipped by VS Code 1.123 and 1.124 produces (fixed upstream in VS Code 1.125; forks such as Cursor pick that up on their own schedule, and
TERM_PROGRAM_VERSION=3.11.13is a Cursor version). That is why it never shows up in iTerm2/tmux here. On our side,/copyon a local macOS session writes the clipboard twice: once throughpbcopy(correct, and what the docs describe as the local path — https://code.claude.com/docs/en/fullscreen) and once through an OSC 52 escape sequence as a safety net. In a terminal with that decoder bug the OSC 52 write lands afterpbcopyand overwrites the good result with the mangled one, which matches everything you saw: the dump file is fine,pbcopy < response.mdfixes it, and ASCII-only text is unaffected. The fullscreen-vs-default and box-drawing correlations are most likely timing (a heavier redraw shifts when the terminal processes the OSC 52 write relative topbcopy) rather than a renderer encoding bug. Claude Code already shows a warning for VS Code 1.123/1.124, but its version check does not recognise Cursor's version numbers, so you got no warning either. Two things would fix this properly on our side: skip the OSC 52 write locally when a native clipboard tool already succeeded on a VS Code-family terminal, and extend the warning to Cursor. In the meantime, a current VS Code build (1.125 or later) or Terminal.app/iTerm2 should give clean pastes; if you can confirm it is clean there, that pins it to the terminal decoder plus our double write.🤖 Generated with Claude Code
We weren't able to reproduce this. Could you provide steps to trigger the issue — what you ran, what happened, and what you expected? This issue will be closed automatically if there's no activity within 7 days.