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
- Use key names the backend recognizes: win/meta instead of cmd/super, alt instead of option, ctrl/shift/alt as modifiers
- Use single characters a-z0-9 directly ("ctrl+a") or check the VK/MODVK tables in win32.mjs for supported names
- Trim whitespace and ensure format is modifier+modifier+key with exactly one final key
- 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
- Stick to ctrl/alt/shift/win modifiers and single alphanumeric keys
- Never use mac-style names (cmd, option) on the Windows backend
- Validate chords against the VK/MODVK vocabulary before dispatch
- Trim inputs and reject empty or trailing '+' segments
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
- coordinates must be finite numbers
- Automation name is required
- Automation prompt is required
- coordinates must be finite numbers
- display index is out of range
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)