Hmbown/CodeWhale · error · ExecError

unknown key combination

Error message

unknown key combination "${text}"

What it means

keyChord parses a human key-combination string like "ctrl+shift+t" into a Windows virtual-key chord for the win32 computer-use backend. It throws this ExecError when either the final key or any modifier token cannot be resolved to a virtual-key code (MODVK/VK lookup fails and it isn't a single alphanumeric).

Solutions

  1. Use key names the backend recognizes: win/meta instead of cmd/super, alt instead of option, ctrl/shift/alt as modifiers
  2. Use single characters a-z0-9 directly ("ctrl+a") or check the VK/MODVK tables in win32.mjs for supported names
  3. Trim whitespace and ensure format is modifier+modifier+key with exactly one final key
  4. Catch ExecError and surface the supported key vocabulary to the calling agent

Example fix

// before
await key("cmd+c");
// after
await key("win+c");
Defensive patterns

Strategy: validation

Validate before calling

const KEY_RE = /^[a-z0-9]+(\+[a-z0-9]+)*$/i;
const KNOWN_MODS = ["ctrl","alt","shift","win"];
function isValidChord(text) {
  if (typeof text !== "string" || !KEY_RE.test(text.trim())) return false;
  const parts = text.toLowerCase().split("+");
  const key = parts.pop();
  return /^[a-z0-9]$/.test(key) || KNOWN_MODS.includes(key) || parts.every(p => KNOWN_MODS.includes(p));
}

Type guard

function isString(v) { return typeof v === "string"; }
const isKnownChord = (t) => isString(t) && isValidChord(t);

Try / catch

try {
  await backend.key("ctrl+shift+t");
} catch (e) {
  if (String(e.message).startsWith("unknown key combination")) {
    throw new Error(`Unsupported key: use names like ctrl/alt/shift/win plus a-z0-9. Got: ${e.message}`);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling a key/key_combo action with an unrecognized key name (e.g. "cmd+c" instead of "win+c", "prtscn", "f13"), an empty string, a trailing "+", or an unknown modifier token.

Common situations: Porting macOS/Linux key names ("cmd", "super", "option") to the Windows backend; typos like "contrl"; passing multi-character keys the VK table lacks; agents inventing key names.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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

Appendix: source

Thrown at crates/tui/plugins/computer-use/src/backends/win32.mjs:244

      for (const code of keys) heldKeys.delete(code);
      return result;
    } catch (failure) {
      try { await releaseInput({ buttons: [], keys }); }
      catch (cleanup) {
        throw Object.assign(new ExecError(`Keyboard input failed: ${failure.message}; release failed: ${cleanup.message}`, failure.result), {
          code: failure.code, cause: failure, cleanupError: cleanup,
        });
      }
      throw failure;
    }
  }

  function keyChord(text) {
    const parts = String(text).split("+").map((part) => part.trim().toLowerCase());
    const key = parts.pop();
    const mods = parts.map((part) => MODVK[part]);
    const vk = VK[key] ?? MODVK[key] ?? (/^[a-z0-9]$/.test(key) ? key.toUpperCase().charCodeAt(0) : null);
    if (vk == null || mods.some((mod) => mod == null)) throw new ExecError(`unknown key combination "${text}"`);
    return { key, vk, mods: [...new Set(mods)] };
  }

  /** Self-contained User32 invocation: prelude + script, fails truthfully. */
  async function withUser32(script, opts) {
    return psOk(`${USER32_PRELUDE}\n${script}`, opts);
  }

  return {
    platform: "win32",
    releaseInput,
    browser_start: browser.start,
    browser_status: browser.status,
    browser_navigate: browser.navigate,
    browser_click: browser.click,
    browser_type: browser.type,
    browser_screenshot: browser.screenshot,
    browser_stop: browser.stop,

View on GitHub (pinned to 73e0f67d83)