Silent data loss in the TUI clipboard path: selection-copy drops a rectangular block of text ("Copied N characters" toast still shown); paste during startup is truncated — no error, prompt submitted corrupted
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?
Related, not a duplicate to be closed into: #74815 (filed 2026-07-06,has repro,area:tui, no maintainer response in six weeks) reports the same defect class from Apple Terminal — selection-copy silently dropping spans mid-word. This report adds (a) the exact geometric signature of the loss (a 26-column rectangular hole), (b) the clipboard payload showing the copy is built from rendered cells (render margin present), (c) a full exoneration of the terminal — different terminal from #74815, same loss, so it is terminal-independent — and (d) a second, 100 %-deterministic loss on startup paste. Please treat #74815 + this as one open wound, not two tickets to be aged out.
Claude Code's fullscreen TUI takes over two things a terminal used to do reliably — text selection/copy and paste — and both can silently lose data. Not "fail": lose. The user gets a green "Copied 3722 characters to clipboard" toast (or a normal [Pasted text #1 +64 lines] chip), submits, and the model receives a prompt with pieces cut out of it. The model then spends real tokens on a mutilated instruction set — in our case it complained "user message cut off mid-sentence; cannot parse task" and kept grinding anyway. Nothing in the UI indicated anything was wrong at any point.
This is worse than the copy/paste being broken outright (#71438, #61021, #49326, #69704 and friends): a broken clipboard is noticed; a lossy clipboard is trusted.
I spent an afternoon proving this is Claude Code and not the terminal. Details below so nobody has to repeat that.
Bug 1 — selection-copy drops a rectangular block (observed, exact signature)
Workflow: a previous session rendered a 3722-char / 65-line prompt as assistant output. User scrolled up in the TUI viewport ("Jump to bottom (click) ↓" toast visible), mouse-dragged across the text; Claude Code auto-copied with its "Copied 3722 characters to clipboard" toast. Pasted into a fresh session as first message.
Diff of the source file vs. what the transcript recorded (~/.claude/projects/<proj>/<session>.jsonl, first user message):
src 3722 chars → received 3535 chars, 187 lost
line 49 col 32-58 of 72 | '- Marker reconciliation uses the' [' ch09 form: deferred marke'] 'rs are diagram'
line 51 col 31-57 of 69 | '- Every editorial insertion is ' ['self-describing in the fil'] 'e (apparatus'
line 53 col 31-57 of 69 | '- Adopted checks: every OCR par' ['agraph tail verified again'] 'st the scan;'
line 55 col 31-36 of 36 | ' ch04→05, ch06→07; ch09 was cl' ['ean).'] ''
line 57 col 31-57 of 74 | ' does not predict is HALT-AND-' ['REPORT, nothing touched. T'] 'he drift register'
line 61 col 31-57 of 71 | 'Confined to sources/mikhailova/' ['edition/ and the report pa'] 'ir. No corpus,'
line 63 col 31-57 of 74 | 'is written; update running tota' ['ls and the coverage record'] ' (five-way form).'
line 65 col 31-57 of 63 | 'Deliver chapter 10 as the next ' ['batch report to the review'] ' seat.'
Eight deletions (ten in the raw clipboard payload), each exactly 26 columns wide, columns 31–57, on alternating rows, spanning the last 17 rows of the selection. That is a hole in a 2-D cell buffer, not a byte-stream fault — byte-stream loss is never column-aligned.
Direct evidence of the clipboard payload itself (the user saved the pasted clipboard to a file, 3674 bytes): it contains the same column-31–57 holes — ten of them; the paste stage is not involved — and, decisively, every line carries the two-space left margin of Claude Code's assistant-output rendering, which is not in the source text. The copied text was assembled from rendered screen cells, not from the message content. That is where the hole comes from: whatever overwrote those cells (overlay, diff-render frame, the "Jump to bottom" toast) between render and drag became "the text". The clipboard producer in this workflow is Claude Code (its own selection model → pbcopy + OSC 52, per setClipboard in the 2.1.233 binary).
I could not re-trigger it on demand today (one clean re-run over a fresh render: 3722/3722). It happened in a session that had just done heavy rendering, with the viewport scrolled up. It is not hypothetical: the corrupted message is in the transcript, timestamped 2026-08-15T15:36:46Z.
Bug 2 — paste during startup is truncated (reproducible, 100%)
Launch claude in a fresh, untrusted directory; deliver a 3722-char bracketed paste ~0.7 s after launch (i.e. while the "Do you trust this folder" dialog is up); accept the dialog; press Enter.
Result: message recorded as 1011 of 3722 chars — a hard cut mid-word ("v1.0 AS AMENDE|D. Governs over…"), remainder discarded, no warning, prompt submitted as if complete.
src 3722 got 1011 lost 2711
delete src[1011:3722] : 'D. Governs over the kickoff wherever they conflict (illustra…'
Input that arrives before the TUI is ready must be either fully buffered or fully rejected. Keeping a prefix and dropping the rest is the one behaviour that is never acceptable.
(Both are the same subsystem — TUI clipboard/input integrity — hence one report. Happy to split if you'd rather.)
What I ruled out (so you don't have to)
All byte-faithful, verified by cmp/diff against source:
- Cmd-V (real NSPasteboard) into a raw-mode pty sink, 23-case corpus (Tibetan, Devanāgarī, CJK, emoji/ZWJ, tabs, trailing/leading whitespace, CRLF, 300-col line, shell metachars)
- Terminal API paste into a sink that ignores stdin for 3 s, 3.7 KB / 22 KB / 110 KB
- Terminal-native selection copy of the same corpus
- OSC 52 clipboard writes 3.7–110 KB, single write / 64-byte chunks / interleaved with rendering noise
- Cmd-V into an idle Claude Code prompt: 3722/3722
- Cmd-V into a fresh Claude Code immediately at the first
❯: 3722/3722 - API paste into Claude Code mid-stream: 3722/3722
The terminal is not the problem. The kernel pty is not the problem. The problem is between Claude Code's render/stdin handling and the message it submits.
Why this matters more than the usual clipboard ticket
- Silent. Every UI signal said success. The only way to detect it was to diff the transcript against the source file.
- Consequential. The corrupted text was an operating brief for a long agentic run. The model consumed context and tool calls on an instruction set with eight holes in it, and the work has to be redone. That is user money and user time spent on your defect.
- Trust. Once a user knows the copy toast can lie, every paste into Claude Code becomes something to verify by hand. That is the opposite of what an agent harness is for.
What Should Happen?
- Selection-copy builds the clipboard text from the logical content model (the message/render tree), not from a screen cell buffer that overlays and diff-frames can trample. Until then, at minimum, verify the copied text length against the selected logical span and refuse (loudly) on mismatch. The "Copied N characters" toast must be true.
- Startup: queue or reject early input atomically. Never keep a prefix and drop the rest.
- Regression tests: paste N KB at t=0/0.5/1/2 s after launch and mid-stream, assert byte equality; selection-copy over a scrolled viewport with the "Jump to bottom" toast showing, assert equality with the source lines.
- A user-visible integrity signal on paste (the chip already shows a line count — make it a byte/char count that matches what will be submitted).
Error Messages/Logs
No error messages — that is the point. Both losses are silent.
Bug 1, source vs transcript (difflib.SequenceMatcher on the recorded user message):
src 3722 chars → received 3535 chars, 187 lost
delete src[2790:2816] (26) ' ch09 form: deferred marke'
delete src[2934:2960] (26) 'self-describing in the fil'
delete src[3069:3095] (26) 'agraph tail verified again'
delete src[3207:3212] (5) 'ean).'
delete src[3317:3343] (26) 'REPORT, nothing touched. T'
delete src[3468:3494] (26) 'edition/ and the report pa'
delete src[3614:3640] (26) 'ls and the coverage record'
delete src[3690:3716] (26) 'batch report to the review'
Raw clipboard payload additionally: delete src[3400:3426] ' is not yours to adjudicat', delete src[3548:3574] 'tions to the .jsonl as the'; plus a 2-space insert at the start of every line (render margin).
Bug 2, startup paste:
src 3722 got 1011 lost 2711
delete src[1011:3722] : 'D. Governs over the kickoff wherever they conflict (illustra…'
Receiving model's reaction (verbatim from the session): "user message cut off mid-sentence; cannot parse task" — then continued working.
Steps to Reproduce
Bug 2 (deterministic, reproduced 1/1 today):
mkdir /tmp/cctest && cd /tmp/cctest(a directory Claude Code has not trusted yet).- Prepare a ~3.7 KB multi-line text (65 lines, ~72 cols) on the clipboard, or have any harness ready to deliver it as a bracketed paste.
- Run
claude. About 0.5–1 s later — while the "Do you trust this folder?" dialog is on screen — paste the text (Cmd-V, or any bracketed paste into the pty). - Press Enter to accept the trust dialog. The prompt shows the paste (or a
[Pasted text …]chip). Press Enter to submit. - Open
~/.claude/projects/<project-dir>/<session>.jsonland compare the firstusermessage to the source text.
Expected: identical. Observed: hard truncation (1011 of 3722 chars in my run), no warning anywhere.
Bug 1 (intermittent; observed once with full evidence, not re-triggered on demand):
- In a session that has produced a lot of output, have the assistant render a ~65-line, ~72-col block of text (e.g. a fenced code block).
- Scroll up in the TUI viewport so the "Jump to bottom (click) ↓" toast is showing.
- Mouse-drag-select the whole block from first line to last (Claude Code's own selection — mouse captured; toast "Copied N characters to clipboard").
pbpaste > out.txtand diff against the source lines.
Expected: identical (modulo the render margin). Observed once: ten 26-column-wide holes at columns 31–57 on alternating rows across the last 17 rows, while the toast reported the full count.
Verification harness I used (a raw-mode pty byte sink that reads until a sentinel, a 23-case Unicode/whitespace corpus, an OSC 52 emitter, and a transcript-vs-source difflib script) available on request — it is what proves the terminal is not involved.
Claude Model
None
Is this a regression?
I don't know
Last Working Version
_No response_
Claude Code Version
2.1.233 (Claude Code) — native install, ~/.local/share/claude/versions/2.1.233
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Other
Additional Information
Environment
- Claude Code 2.1.233, fullscreen TUI, mouse captured (selection-copy mode active); Max subscription
- macOS 26.6.1 (25G76), Apple M4 Max
- Terminal: cmux 0.64.22 (Ghostty 1.3.2 core),
TERM_PROGRAM=ghostty,TERM=xterm-256color, terminal copy-on-select enabled. Local pty; no tmux/screen/ssh. - Clipboard path per your own
setClipboard:pbcopyand OSC 52 emitted (both carry the same, already-holed text — the terminal's OSC 52 handling was separately verified faithful to 110 KB).
Model in the affected session: claude-fable-5 (irrelevant to the defect — this is deterministic harness code, not model behaviour).
Regression? Unknown. The selection-copy mode itself is recent (fullscreen TUI); the failure was first noticed today.
Impact statement, for whoever triages this: a paying user lost a full agentic run's worth of tokens to a corrupted brief that every UI signal said was fine, then spent an afternoon proving the defect is yours and not the terminal's, and now has a standing rule that nothing generated by Claude Code may be moved by clipboard — everything goes to disk and gets checksummed. That rule should not have to exist.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗