Repository navigation
emrg: a clipboard image the TUI cannot extract leaves a 0-byte file, and the paste path reports nothing #1926
Description
A clipboard image the TUI cannot extract leaves a 0-byte file in the session's images/ directory, and on the paste path it says nothing at all. Found 2026-10-08 (cycle cyc20261008-150345) while re-measuring the image rant's format-parity item.
The two defects
1. The litter. Every branch of _extract_clipboard_image (emrg/client/app.py) opens its target before the data arrives:
- macOS: the AppleScript does
open for access (POSIX file …) with write permission, andopen for accesscreates the file; - Linux:
open(target_path, 'wb')truncates it; - Windows:
$img.Save(...)can write a header and then fail.
When the write then fails, the function returned path.exists() and path.stat().st_size > 0 → False, leaving the file behind. Nothing ever removes a _clipboard_tmp_N.png.
2. The silence on the paste path. The paste branch is:
if _extract_clipboard_image(str(tmp_path)):
... insert the [📷 label] placeholder ...
# no else — and then unconditionally `term.render(); return True`So an advertised image that produced no bytes is indistinguishable from a paste that carried no image — the same class of report as issue #1785 ("Cmd+V does nothing"), on the one path that report was about. The /image token path has had an else with a visible message (无法从剪贴板提取图片。) all along; the paste path never did.
The measurement (executed, not read)
Run on macOS against a scratch path with the AppleScript path's own two steps — open for access, then a write whose coercion fails:
ls probe-clip.png -> No such file or directory
osascript -e 'set f to open for access (POSIX file "…/probe-clip.png") with write permission' \
-e 'set eof f to 0' -e 'try' -e ' write (the clipboard as «class PNGf») to f' -e 'end try' \
-e 'close access f'
ls -l probe-clip.png -> -rw-r--r-- 1 argszero staff 0 probe-clip.png
0 bytes, created by the attempt itself. That is exactly what happens when the clipboard advertises an image flavour the extractor cannot convert: _detect_clipboard_image accepts «class TIFF», while _extract_clipboard_image always writes the «class PNGf» flavour — so a TIFF-only clipboard passes detection and then produces nothing.
What the change does
_clipboard_extraction_verdict(target_path)— the verdict and the cleanup are one decision: a target holding no bytes is removed and reported as a failure, so no caller can keep the litter by forgetting a branch. All three platform branches go through it._report_clipboard_extraction_failure(chat, target_path)— one wording, one log line, used by both paths. The paste branch gains theelseit never had.
Acceptance
- A failed extraction leaves no file: drive the verdict helper with a 0-byte file →
Falseand the file is gone; with a real image →Trueand it is kept; with a missing path →False. - Every platform branch decides through that one function (a branch that tests the file for itself reintroduces the 0-byte file on that platform only).
- Both clipboard paths report the failure, with one copy of the wording.
- Mutation: removing the cleanup, removing the paste
else, making the Linux branch self-decide, or duplicating the wording each turns the corresponding test red (all four run).
Limit, named: the two decisions are tested directly; the wiring is asserted as source shape, because the branches and call sites live inside handle_key, which needs a terminal and a socket. Nothing here proves a real paste reaches them.
Related but not part of this: the image rant 2026-09-30T09:35:04 (item (b), format parity) is untouched — its premise is about the GUI's whitelist, and this issue is about the TUI's extraction path.
Activity
argszero commentedon Oct 8, 2026
Handled by #1927