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

  1. Verify DISPLAY (X11) or WAYLAND_DISPLAY/Wayland socket is set in the environment the backend runs in
  2. Confirm the needed binary is installed and try it manually: `xclip -selection clipboard -o` or `wl-paste`
  3. For Wayland, check the tool supports the clipboard's mime type, or copy something first so the selection is owned
  4. 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

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


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)