Hmbown/CodeWhale · error

computer action " " requires id

Error message

computer action "${args.action}" requires id

What it means

Argument-validation guard in resolveTool for 'computer': the action requires addressing an existing computer (switch/remove etc.), but the id field is missing from the args. The request never reaches the wire layer.

Solutions

  1. Pass the target computer's id
  2. Call action "list" first to enumerate computer ids
  3. Verify the action is actually "list" if you intended an id-less call

Example fix

// before
resolveTool("computer", { action: "switch" })
// after
resolveTool("computer", { action: "switch", id: "vm-7" })
Defensive patterns

Strategy: validation

Validate before calling

if (args.action !== 'list' && args.id == null) throw new Error(`computer ${args.action} requires id`);

Type guard

function computerIdProvided(a) { return a.action === 'list' || (a.id !== undefined && a.id !== null); }

Try / catch

try { resolveTool('computer', args); } catch (e) { if (String(e.message).includes('requires id')) { /* call computer list, pick id, retry */ } else throw e; }

Prevention

When it happens

Trigger: resolveTool("computer", { action: "remove" }) without id; id:null; intending "list" but passing "switch".

Common situations: A caller removes or switches to a computer without knowing its id; the model omits the id; action typo making list become another action.

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/3a096379a21ee592. Report an issue: GitHub.

Appendix: source

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

        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: {} };
      if (rest.id == null) throw bad(`computer action "${args.action}" requires id`);
      const id = rest.id;
      delete rest.id;
      return { name: wire, args: { ...rest, computer: id } };
    }
    case "consent": {
      const rest = { ...args };
      delete rest.action;
      const wire = { status: "consent_status", allow: "consent_allow", deny: "consent_deny", revoke: "consent_revoke" }[args.action];
      if (!wire) throw bad(`consent action must be status, allow, deny or revoke (got ${JSON.stringify(args.action)})`);
      if (args.action === "status") return { name: wire, args: { computer: rest.computer } };
      const foreground = rest.scope === "foreground";
      if (!foreground && rest.app == null && rest.name == null && rest.bundle_id == null && rest.pid == null) {
        throw bad(`consent action "${args.action}" needs an app (name, bundle_id, pid or app string) — or scope:"foreground" for the shared-pointer decision`);
      }
      return { name: wire, args: rest };
    }
    case "key": {
      if (args.duration == null) return { name, args };

View on GitHub (pinned to 73e0f67d83)