Hmbown/CodeWhale · error · ExecError
clipboard read failed
Error message
clipboard read failed
What it means
The Linux computer-use backend's read_clipboard handler runs xclip/xsel (X11) or wl-paste (Wayland) to read the system clipboard. If the spawned command exits nonzero within the 10s timeout, the backend throws this ExecError with the process result attached. It indicates the clipboard tool ran but failed to produce clipboard content.
Solutions
- Verify DISPLAY (X11) or WAYLAND_DISPLAY/Wayland socket is set in the environment the backend runs in
- Confirm the needed binary is installed and try it manually: `xclip -selection clipboard -o` or `wl-paste`
- For Wayland, check the tool supports the clipboard's mime type, or copy something first so the selection is owned
- Retry the read; transient selection-ownership races after a clipboard-manager restart are common
Example fix
// before
const text = await readClipboard();
// after
let text;
try { text = await readClipboard(); }
catch (e) { console.warn('clipboard empty or unavailable:', e.message); text = ''; } Defensive patterns
Strategy: fallback
Validate before calling
const bin = isX11 ? (tools.xclip ? 'xclip' : 'xsel') : 'wl-paste';
const ok = !!tools[bin === 'xclip' ? 'xclip' : bin] || which(bin);
if (!ok) throw new SkipError('no clipboard tool available'); Try / catch
try { text = await readClipboard(); } catch (e) { text = ''; log.warn('clipboard read unavailable', e.message); } Prevention
- Check DISPLAY/WAYLAND_DISPLAY before enabling clipboard features
- Pre-check tool availability once at backend init
- Treat clipboard reads as best-effort and degrade to empty text
When it happens
Trigger: Calling read_clipboard when the X11 clipboard is empty/unowned (xclip exits 1), when xclip/xsel cannot connect to the display, when wl-paste fails under Wayland (no clipboard manager, or no data for the requested mime type), or when the tool crashes.
Common situations: Headless/SSH sessions without DISPLAY or WAYLAND_DISPLAY set; running the tool inside a container without access to the compositor; choosing xsel on a desktop where it was never started with a daemon; stale xclip process holding the selection after a clipboard-manager restart.
Related errors
- PRIMARY selection busy or unavailable
- cursor position needs an X11 session in this build
- linux backend needs " " for — install it and retry
- scroll on Wayland is not available in this build; use…
- could not parse xdotool getmouselocation output
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/a9f8e39a1e62ef7f.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/backends/linux.mjs:748
if match is None and want == "click":
match = next((n for n in names if n.lower() in ("click", "press", "activate")), None)
if match is None:
print(json.dumps({"ok": False, "code": "action_not_found: " + ",".join(names)}))
else:
a.doAction(names.index(match))
print(json.dumps({"ok": True, "sent": True}))`;
const out = await atspiResolve(target, body, String(action));
if (!out.ok) throw new ExecError(`perform_action failed: ${out.code}`);
return { action_sent: true, strategy: "a11y", action };
},
read_clipboard: async () => {
await probeSession();
const cmd = session === "x11"
? (tools.xclip ? ["xclip", "-selection", "clipboard", "-o"] : ["xsel", "--clipboard", "--output"])
: ["wl-paste"];
need(cmd[0], "clipboard read");
const r = await run(cmd[0], cmd.slice(1), { timeoutMs: 10_000 });
if (r.code !== 0) throw new ExecError("clipboard read failed", r);
return { text: r.stdout, encoding: "utf8" };
},
write_clipboard: async ({ text }) => {
await probeSession();
const cmd = session === "x11"
? (tools.xclip ? ["xclip", "-selection", "clipboard"] : ["xsel", "--clipboard", "--input"])
: ["wl-copy"];
need(cmd[0], "clipboard write");
spawnDetached(cmd[0], cmd.slice(1), String(text ?? ""), true);
return { written: String(text ?? "").length };
},
cursor_position: async () => {
await probeSession();
if (session === "x11") {
const out = await xdotool(["getmouselocation"]);
const m = /x:(-?\d+)\s+y:(-?\d+)/.exec(out);
if (!m) throw new ExecError(`could not parse xdotool getmouselocation output: ${out}`);
return { x: Number(m[1]), y: Number(m[2]) };View on GitHub (pinned to 73e0f67d83)