Hmbown/CodeWhale · error

clipboard action "write" requires text

Error message

clipboard action "write" requires text

What it means

resolveTool's clipboard case: action 'write' was given without a string text argument; the write cannot proceed without content, so the tool call is rejected with a bad_args-shaped error before any backend dispatch.

Solutions

  1. Add a string `text` field to the arguments
  2. If the content is under another key, rename it to `text`
  3. Stringify non-string payloads before passing them

Example fix

// before
resolveTool("clipboard", { action: "write", content: "hello" })
// after
resolveTool("clipboard", { action: "write", text: "hello" })
Defensive patterns

Strategy: validation

Validate before calling

if (args.action === 'write' && typeof args.text !== 'string') throw new Error('clipboard write needs string text');

Type guard

function isWritableClipboardArgs(a) { return typeof a.text === 'string'; }

Prevention

When it happens

Trigger: resolveTool("clipboard", { action: "write" }) with no text, text: undefined, text: 123, or a non-string object.

Common situations: A model omits the text field for a clipboard write; a caller passes the content under a different key like "value" or "content"; text is a number the caller forgot to stringify.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/c80bc86103695c7c. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/plugins/computer-use/src/tools.mjs:786

        : button === "middle" && clicks === 1 ? "middle_click"
        : null;
      if (!wire) throw bad(`click supports left with 1-3 clicks, right x1 or middle x1 (got ${JSON.stringify(button)} x${clicks})`);
      if (button !== "left") delete rest.strategy; // strategy is an a11y-left-click concept
      return { name: wire, args: rest };
    }
    case "pointer": {
      const rest = { ...args };
      delete rest.action;
      const wire = { move: "mouse_move", down: "left_mouse_down", up: "left_mouse_up" }[args.action];
      if (!wire) throw bad(`pointer action must be "move", "down" or "up" (got ${JSON.stringify(args.action)})`);
      return { name: wire, args: rest };
    }
    case "clipboard": {
      const rest = { ...args };
      delete rest.action;
      if (args.action === "read") return { name: "read_clipboard", args: { computer: rest.computer } };
      if (args.action === "write") {
        if (typeof rest.text !== "string") throw bad("clipboard action \"write\" requires text");
        return { name: "write_clipboard", args: { text: rest.text, computer: rest.computer } };
      }
      throw bad(`clipboard action must be "read" or "write" (got ${JSON.stringify(args.action)})`);
    }
    case "recording": {
      const rest = { ...args };
      delete rest.action;
      const wire = { start: "recording_start", stop: "recording_stop", status: "recording_status", list: "recording_list" }[args.action];
      if (!wire) throw bad(`recording action must be start, stop, status or list (got ${JSON.stringify(args.action)})`);
      if ((args.action === "stop" || args.action === "status") && rest.id == null) throw bad(`recording action "${args.action}" requires id`);
      return { name: wire, args: rest };
    }
    case "computer": {
      const rest = { ...args };
      delete rest.action;
      const wire = { list: "computer_list", switch: "computer_switch", register: "computer_register", spawn: "computer_spawn", remove: "computer_remove" }[args.action];
      if (!wire) throw bad(`computer action must be list, switch, register, spawn or remove (got ${JSON.stringify(args.action)})`);
      if (args.action === "list") return { name: wire, args: {} };

View on GitHub (pinned to 73e0f67d83)