moeru-ai/airi · error · Error

Invalid accelerator: empty string

Error message

Invalid accelerator: empty string

What it means

`parseAccelerator(input)` parses a shortcut string like `"Mod+Shift+K"` into a structured `ShortcutAccelerator`. It throws `Invalid accelerator: empty string` when `input.trim()` has length 0, i.e. the caller passed `""`, `" "`, or a value that becomes empty after trimming. Parsing happens before any tokenization, so no other validation runs. Whitespace-only strings are treated identically to the empty string.

Source

Thrown at packages/stage-shared/src/global-shortcut/accelerators.ts:315

 *   canonical key
 *
 * Throws:
 * - `Error` when the input is empty, has empty tokens, names an
 *   unknown key, repeats a modifier, or contains multiple non-modifier
 *   tokens
 *
 * @example
 *   parseAccelerator('Mod+Shift+K')
 *   // => { modifiers: ['cmd-or-ctrl', 'shift'], key: 'KeyK' }
 *
 * @example
 *   parseAccelerator(' CmdOrCtrl + Shift + KeyK ')
 *   // => same as above; whitespace tolerated
 */
export function parseAccelerator(input: string): ShortcutAccelerator {
  const trimmed = input.trim()
  if (trimmed.length === 0)
    throw new Error('Invalid accelerator: empty string')

  const rawTokens = trimmed.split('+')
  const modifiers: ShortcutModifier[] = []
  let key: ShortcutKey | undefined

  for (const raw of rawTokens) {
    const token = raw.trim()
    if (token.length === 0)
      throw new Error(`Invalid accelerator "${input}": empty token`)

    const modifier = lookupModifierToken(token)
    if (modifier !== undefined) {
      if (modifiers.includes(modifier))
        throw new Error(`Invalid accelerator "${input}": duplicate modifier "${modifier}"`)
      modifiers.push(modifier)
      continue
    }

View on GitHub (pinned to 27111382b4)

Solutions

  1. Guard the input before parsing: `if (!input?.trim()) return` or use the provided `isValidAccelerator(input)` / `tryParseAccelerator` helper if available.
  2. Treat an empty binding as 'no shortcut' in your settings model (store `null` rather than `''`).
  3. Validate in the settings UI: disable the save/apply action while the field is empty.
  4. If parsing user input live, skip the `parseAccelerator` call until the string is non-empty.

Example fix

// before
const acc = parseAccelerator(settings.globalShortcut ?? '')

// after
const raw = settings.globalShortcut
if (!raw || !raw.trim()) return  // treat as unbound
const acc = parseAccelerator(raw)
Defensive patterns

Strategy: validation

Validate before calling

function shouldParseAccelerator(input: unknown): input is string {
  return typeof input === 'string' && input.trim().length > 0
}

if (shouldParseAccelerator(raw)) parseAccelerator(raw)

Type guard

function isNonEmptyAcceleratorString(input: unknown): input is string {
  return typeof input === 'string' && input.trim().length > 0
}

Try / catch

try {
  const acc = parseAccelerator(raw)
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Invalid accelerator')) {
    // treat as unbound; do not register
  } else throw e
}

Prevention

When it happens

Trigger: Calling `parseAccelerator('')`, `parseAccelerator(' ')`, or passing a variable that resolved to an empty/whitespace string (e.g. a settings field that was never filled in, a form input before the user typed anything, or a destructured config value that defaulted to `''`).

Common situations: Loading a global-shortcut binding from persisted settings where the field was saved blank; binding a keybind editor to a reactive ref before the user enters a value; reading a YAML/JSON config key that is present but empty; passing `undefined`-derived defaults that coerce to `''`.

Related errors


AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12). Data as JSON: /api/errors/227b0398962d7693. Report an issue: GitHub.