neoclide/coc.nvim · error

Invalid key ${name} of registerKeymap

Error message

Invalid key ${name} of registerKeymap

What it means

registerKeymap requires a non-empty name because it generates a global <Plug>(coc-<name>) mapping. An empty/falsy name cannot form a valid mapping, so registration throws immediately.

Source

Thrown at src/core/keymaps.ts:77

    if (res == null) return defaultReturn
    return res as string
  }

  public async doInsertKeymap(key: string, ...args: any[]): Promise<InsertKeymapResult> {
    let fn = this.insertKeymaps.get(key)
    if (!fn) {
      logger.error(`insert keymap for ${key} not found`)
      return []
    }
    let res = await Promise.resolve(fn(...args))
    return Array.isArray(res) ? res : []
  }

  /**
   * Register global <Plug>(coc-${key}) key mapping.
   */
  public registerKeymap(modes: MapMode[], name: string, fn: KeymapCallback, opts: KeymapOption = {}): Disposable {
    if (!name) throw new Error(`Invalid key ${name} of registerKeymap`)
    let key = `coc-${name}`
    if (this.keymaps.has(key)) throw new Error(`keymap: "${name}" already exists.`)
    const lhs = `<Plug>(${key})`
    opts = Object.assign({ sync: true, cancel: true, silent: true, repeat: false }, opts)
    let { nvim } = this
    this.keymaps.set(key, [fn, !!opts.repeat])
    let method = opts.sync ? 'request' : 'notify'
    for (let mode of modes) {
      if (mode == 'i') {
        const cancel = opts.cancel ? 1 : 0
        nvim.setKeymap(mode, lhs, `coc#_insert_key('${method}', '${key}', ${cancel})`, {
          expr: true,
          noremap: true,
          silent: opts.silent
        })
      } else {
        nvim.setKeymap(mode, lhs, `:${getKeymapModifier(mode, opts.cmd)}call coc#rpc#${method}('doKeymap', ['${key}'])<cr>`, {
          noremap: true,

View on GitHub (pinned to 50e974d969)

Solutions

  1. Pass a non-empty name string to registerKeymap
  2. Fix the dynamic value used as the keymap name
  3. Validate inputs before calling the API

Example fix

// before
keymaps.registerKeymap(['n'], name, fn) // name === ''
// after
if (!name) return
keymaps.registerKeymap(['n'], name, fn)
Defensive patterns

Strategy: validation

Validate before calling

const valid = typeof name === 'string' && name.length > 0
if (!valid) throw new TypeError('keymap name must be a non-empty string')

Type guard

const isValidKeymapName = (n): n is string => typeof n === 'string' && n.length > 0

Try / catch

try {
  keymaps.registerKeymap(['n'], name, handler)
} catch (e) {
  if (String(e.message).startsWith('Invalid key')) logger.error(`bad keymap name: ${JSON.stringify(name)}`)
  else throw e
}

Prevention

When it happens

Trigger: Calling keymaps.registerKeymap(['n'], '', fn) or with a variable that is undefined due to a bad import/config.

Common situations: Extension keymap registration built from dynamic values that resolve to empty strings; copy-pasted registration code missing the name argument.

Related errors


AI-assisted analysis of neoclide/coc.nvim@50e974d969 (2026-08-31). Data as JSON: /api/errors/138d7b542cef7021. Report an issue: GitHub.