moeru-ai/airi · error · Error
Invalid accelerator "${input}": multiple non-modifier keys (
Error message
Invalid accelerator "${input}": multiple non-modifier keys ("${key}", "${token}") What it means
The parser allows exactly one non-modifier key token. The first non-modifier token is stored in `key`; if a second non-modifier token is encountered (i.e. `key !== undefined`), it throws `Invalid accelerator "<input>": multiple non-modifier keys ("<key>", "<token>")`. Both offending tokens are included in the message.
Source
Thrown at packages/stage-shared/src/global-shortcut/accelerators.ts:335
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
}
if (key !== undefined)
throw new Error(`Invalid accelerator "${input}": multiple non-modifier keys ("${key}", "${token}")`)
key = normalizeKeyToken(token)
}
if (key === undefined)
throw new Error(`Invalid accelerator "${input}": no key token`)
return { modifiers, key }
}
/**
* Tests whether `input` is a well-formed accelerator string.
*
* Use when:
* - Gating user input without needing the parsed result
*
* Returns:
* - `true` when `parseAccelerator` would succeed, `false` otherwise
*/View on GitHub (pinned to 27111382b4)
Solutions
- If you need a key sequence, store two separate `ShortcutAccelerator` values, not one string.
- Validate single-key intent in the recorder before serialization.
- Run `isValidAccelerator(input)` on user input and surface a friendly message.
- Inspect the two tokens in the error to find which key was extra.
Example fix
// before
parseAccelerator('Ctrl+A+B') // throws
// after
// represent the sequence as two bindings
const combo1 = parseAccelerator('Ctrl+A')
const combo2 = parseAccelerator('Ctrl+B') Defensive patterns
Strategy: validation
Validate before calling
function countNonModifierTokens(input: string): number {
return input.split('+').map(t => t.trim()).filter(t => lookupModifierToken(t) === undefined && t.length > 0).length
}
if (countNonModifierTokens(raw) === 1) parseAccelerator(raw) Type guard
function hasSingleKey(input: string): boolean {
return countNonModifierTokens(input) === 1
} Try / catch
try {
parseAccelerator(raw)
} catch (e) {
if (e instanceof Error && e.message.includes('multiple non-modifier keys')) {
// split into two separate bindings
} else throw e
} Prevention
- Represent key sequences as multiple bindings, not one accelerator.
- Recorder should close the combo after one non-modifier key.
- Validate single-key intent before serialization.
When it happens
Trigger: Inputs such as `"Ctrl+A+B"`, `"KeyK+KeyL"`, `"Shift+F1+F2"`, or any string where two tokens survive `lookupModifierToken` as non-modifiers. Also `"A+B"` with no modifiers.
Common situations: A chord/sequence UI that tried to express a multi-keystroke shortcut as one accelerator (accelerators are single combos, not sequences); user typing a second character into a single-key field; merging two shortcuts accidentally.
Related errors
- Invalid accelerator: empty string
- Invalid accelerator "${input}": empty token
- Invalid accelerator "${input}": duplicate modifier "${modifi
- Invalid accelerator "${input}": no key token
- Invalid accelerator: unknown key "${token}"
AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12).
Data as JSON: /api/errors/eae784308a09ffc5.
Report an issue: GitHub.