moeru-ai/airi · error · Error
Invalid accelerator "${input}": empty token
Error message
Invalid accelerator "${input}": empty token What it means
`parseAccelerator` splits the trimmed input on `+` and trims each token. If any resulting token has length 0, it throws `Invalid accelerator "<input>": empty token`. This means the string contains a `+` with nothing (or only whitespace) on one side of it. The original `input` is echoed in the message so the malformed region is visible.
Source
Thrown at packages/stage-shared/src/global-shortcut/accelerators.ts:324
* // => { 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
}
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 }View on GitHub (pinned to 27111382b4)
Solutions
- Sanitize the string before parsing: collapse repeated `+` and strip leading/trailing `+` (`input.replace(/\+{2,}/g, '+').replace(^\+|\+$/g, '').trim()`).
- Use `isValidAccelerator(input)` to gate the parse on user-supplied values.
- Reconstruct the accelerator programmatically from a structured `{ modifiers, key }` via `formatAccelerator` instead of hand-concatenating strings.
- Inspect the echoed `<input>` in the message to locate the stray separator.
Example fix
// before
const acc = parseAccelerator(rawUserInput)
// after
const clean = rawUserInput.replace(/\+{2,}/g, '+').replace(/^\+|\+$/g, '').trim()
if (!clean) return
const acc = parseAccelerator(clean) Defensive patterns
Strategy: validation
Validate before calling
function sanitizeAccelerator(input: string): string {
return input.replace(/\+{2,}/g, '+').replace(/^\+|\+$/g, '').trim()
}
const clean = sanitizeAccelerator(raw)
if (clean) parseAccelerator(clean) Type guard
function isWellFormedAccelerator(input: string): boolean {
const trimmed = input.trim()
if (!trimmed) return false
return trimmed.split('+').every(tok => tok.trim().length > 0)
} Try / catch
try {
parseAccelerator(raw)
} catch (e) {
if (e instanceof Error && e.message.includes('empty token')) {
// re-prompt the user for the keybind
} else throw e
} Prevention
- Do not hand-concatenate accelerator strings; build them from structured modifiers+key.
- Strip stray separators and collapse repeated '+' before parsing.
- Validate with the library's isValidAccelerator helper on user input.
When it happens
Trigger: Inputs such as `"Ctrl++K"`, `"+K"`, `"K+"`, `"Ctrl+ +K"` (whitespace-only segment), `"Mod+"`, or any value where `trimmed.split('+')` yields an empty/whitespace element after per-token `.trim()`.
Common situations: Typos in hand-authored keybind config (`"Mod + + K"`); concatenating modifiers with a stray separator (`[mod, '', key].join('+')`); copy-paste from docs that used an em-dash or special plus character; a keystroke recorder that emits an empty segment between two key events.
Related errors
- Invalid accelerator: empty string
- Invalid accelerator "${input}": duplicate modifier "${modifi
- Invalid accelerator "${input}": multiple non-modifier keys (
- 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/9e9e3342de7d4715.
Report an issue: GitHub.