Hmbown/CodeWhale · error · ExecError
unknown key " " (supported: + modifiers…
Error message
unknown key "${p}" (supported: ${Object.keys(KEY_CODES).join(", ")} + modifiers cmd/ctrl/alt/shift/fn) What it means
Every '+'-separated token must be either a known modifier (cmd/ctrl/alt/shift/fn) or a key in the backend's KEY_CODES table. Any unrecognized token is rejected, and the message enumerates the supported key names so the caller can correct it.
Solutions
- Use a key name from the supported list printed in the error message
- Map platform aliases before calling: 'win'/'meta' -> 'cmd', 'esc' -> 'escape' if that is the table's name
- Extend/consult the KEY_CODES table for the exact accepted names
- Trim and lowercase input (parseChord already lowercases, so fix spelling rather than case)
Example fix
// before
await press("win+c");
// after
await press("cmd+c"); Defensive patterns
Strategy: validation
Validate before calling
const ALIAS = { win: "cmd", meta: "cmd", super: "cmd", esc: "escape", return: "enter" };
const normalized = key.split("+").map(p => ALIAS[p.trim().toLowerCase()] ?? p.trim().toLowerCase()).join("+"); Try / catch
try {
await press(key);
} catch (e) {
if (e instanceof ExecError && e.message.startsWith("unknown key")) {
const supported = e.message.match(/supported: ([^+]+)/)?.[1];
throw new Error(`key '${key}' unsupported; use one of: ${supported}`);
}
throw e;
} Prevention
- Keep an alias map from Windows/web key names to macOS backend names
- Validate against the KEY_CODES list (printed in the error) at your boundary
- Prefer lowercase canonical names from the backend's documentation
When it happens
Trigger: Passing key names not in KEY_CODES, e.g. 'win', 'meta', 'return' (if table uses 'enter'), 'spacebar', 'esc' vs 'escape', uppercase (input is lowercased, so this is safe), or accented/symbol characters.
Common situations: Cross-platform key naming habits (Windows key names on macOS backend); typos like 'cmnd'; assuming alias coverage the table does not have.
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/63631cb87bf04f4c.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/plugins/computer-use/src/backends/darwin.mjs:493
try {
await action();
// The acknowledgement carries the yield_ms the helper waited for a
// hardware-input gap before posting the press.
return lease.receipt;
} finally {
await withSignal(null, () => lease.release());
}
}
function parseChord(text) {
const parts = String(text).split("+").map((s) => s.trim().toLowerCase()).filter(Boolean);
if (!parts.length) throw new ExecError("empty key text");
let flags = 0;
let key = null;
for (const p of parts) {
if (MODIFIERS[p] != null) flags |= MODIFIERS[p];
else if (KEY_CODES[p] != null) { if (key) throw new ExecError(`multiple non-modifier keys in "${text}"`); key = p; }
else throw new ExecError(`unknown key "${p}" (supported: ${Object.keys(KEY_CODES).join(", ")} + modifiers cmd/ctrl/alt/shift/fn)`);
}
if (key == null) throw new ExecError(`no non-modifier key in "${text}"`);
return { flags, code: KEY_CODES[key], key };
}
// ---------- displays ----------
async function displayInfo() { return native("displays"); }
// ---------- screenshots ----------
function recordingsDir() {
return process.env.CODEWHALE_CU_RECORDINGS_DIR || path.join(os.homedir(), ".codewhale-cu", "recordings");
}
async function screenshot({ display, region, app_ref, window_id, path: outPath } = {}) {
// Once an app is selected, ordinary observations follow it behind the
// user's work. An explicit display/region remains a deliberate desktop capture.
if (app_ref === undefined && display === undefined && region === undefined) app_ref = state.inputApp ?? undefined;
const dir = recordingsDir();View on GitHub (pinned to 73e0f67d83)