{"record":{"id":"10b6f8b818452324","repo":"moeru-ai/airi","slug":"invalid-accelerator-unknown-key-token","errorCode":null,"errorMessage":"Invalid accelerator: unknown key \"${token}\"","messagePattern":"Invalid accelerator: unknown key \"(.+?)\"","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/stage-shared/src/global-shortcut/accelerators.ts","lineNumber":270,"sourceCode":"    return token\n\n  const aliased = KEY_ALIASES.get(token)\n  if (aliased !== undefined)\n    return aliased\n\n  if (SINGLE_LETTER_RE.test(token)) {\n    const candidate = `Key${token.toUpperCase()}`\n    if (LETTER_KEYS.has(candidate))\n      return candidate\n  }\n\n  if (SINGLE_DIGIT_RE.test(token)) {\n    const candidate = `Digit${token}`\n    if (DIGIT_KEYS.has(candidate))\n      return candidate\n  }\n\n  throw new Error(`Invalid accelerator: unknown key \"${token}\"`)\n}\n\n/**\n * Returns the canonical modifier for a token, or `undefined` if the\n * token is not a modifier (i.e. probably a key).\n */\nfunction lookupModifierToken(token: string): ShortcutModifier | undefined {\n  return MODIFIER_ALIASES.get(token.toLowerCase())\n}\n\n/**\n * Parses a string accelerator into its canonical structured form.\n *\n * Use when:\n * - Accepting an accelerator from author code, settings UI, or config\n *   file\n * - Validating user input\n *","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/moeru-ai/airi/blob/27111382b4a79a7e983289d6e983a06af185ed0f/packages/stage-shared/src/global-shortcut/accelerators.ts#L252-L288","documentation":"Thrown by `normalizeKeyToken()` in the global-shortcut accelerators module when a key token cannot be matched against any known key. The normalizer first checks the canonical `KEY_NAMES` set, then a small `KEY_ALIASES` map, then single-letter (`Key<A-Z>`) and single-digit (`Digit<0-9>`) shorthand; if none match, the token is rejected as an unknown key. This runs as part of `parseAccelerator()` for the non-modifier token of the accelerator string.","triggerScenarios":"Calling `parseAccelerator(input)` where the key token is not a recognized name, alias, single letter, or single digit — e.g. `CmdOrCtrl+F1` (function keys not in KEY_NAMES), `Ctrl+??`, `Shift+foobar`, or a token with stray punctuation. Whitespace is trimmed before matching, but unknown multi-character key names still fail.","commonSituations":"User-configured or settings-file shortcuts using key names the parser does not recognize (function keys, numpad names, locale-specific keys, punctuation not in the alias map); typos; accelerators copied from another app's format that uses different key names.","solutions":["Use a key token the parser recognizes: a single letter (`K`), single digit (`5`), a canonical W3C code (`KeyK`, `Digit5`, `ArrowUp`, `Escape`), or an alias (`Up`, `Esc`).","Check `KEY_NAMES` and `KEY_ALIASES` in the module for the accepted token set before authoring the accelerator.","If you need a key not yet supported (e.g. function keys), extend `KEY_NAMES`/`KEY_ALIASES` and ensure the Electron serialization overrides cover it, rather than passing an unknown token.","Validate user-provided accelerator strings with `parseAccelerator` in a try/catch and surface a clear error in the settings UI."],"exampleFix":"// before\nparseAccelerator('CmdOrCtrl+F1') // F1 not in KEY_NAMES\n\n// after\nparseAccelerator('CmdOrCtrl+P')","handlingStrategy":"try-catch","validationCode":"import { parseAccelerator } from '@proj-airi/stage-shared/global-shortcut/accelerators'\n\nfunction tryParseAccelerator(input: string) {\n  try {\n    return { accelerator: parseAccelerator(input), error: undefined }\n  } catch (e) {\n    return { accelerator: undefined, error: e as Error }\n  }\n}\n\nconst { accelerator, error } = tryParseAccelerator(userInput)\nif (error) showUser(`Invalid shortcut: ${error.message}`)","typeGuard":"const SINGLE_LETTER_RE = /^[A-Z]$/i\nconst SINGLE_DIGIT_RE = /^\\d$//\n\nfunction looksLikeValidKeyToken(token: string): boolean {\n  return SINGLE_LETTER_RE.test(token) || SINGLE_DIGIT_RE.test(token) || KEY_NAMES.has(token) || KEY_ALIASES.has(token)\n}\n\n// NOTE: KEY_NAMES and KEY_ALIASES must be imported/re-exported from the module to use this guard in caller code.","tryCatchPattern":"try {\n  const accel = parseAccelerator(input)\n  register(accel)\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Invalid accelerator:')) {\n    showUser(`That shortcut key is not recognized. Use a letter, digit, or a known key name.`)\n    return\n  }\n  throw e\n}","preventionTips":["Use single letters, single digits, canonical W3C codes (KeyK, Digit5, ArrowUp, Escape), or known aliases (Up, Esc).","Consult KEY_NAMES and KEY_ALIASES in the module for the accepted token set.","Validate user-provided accelerator strings with parseAccelerator in try/catch and surface a friendly message.","If you need a new key (e.g. function keys), extend KEY_NAMES/KEY_ALIASES and Electron overrides rather than passing unknown tokens."],"tags":["global-shortcut","accelerator","parsing","validation","electron"],"backgroundTag":null,"analyzedSha":"27111382b4a79a7e983289d6e983a06af185ed0f","analyzedAt":"2026-08-12T18:33:34.132Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}