neoclide/coc.nvim · error · Error

Invalid action ${action}

Error message

Invalid action ${action}

What it means

ListMappings.getAction resolves a list action name either to a registered action or to a key:expression pair (e.g. 'j:myexpr'). If the string is neither a known action nor a valid '<knownKey>:<expr>' form (missing expression or unknown key), it throws so the caller knows the mapping is invalid.

Source

Thrown at src/list/mappings.ts:298

    if (Array.isArray(key)) {
      for (let k of key) {
        mappings.set(k, fn)
      }
    } else {
      mappings.set(key, fn)
    }
  }

  private addAction(key: string, fn: (expr?: string) => void | Promise<void>): void {
    this.actions.set(key, fn)
  }

  public getAction(action: string): () => void | Promise<void> {
    if (this.actions.has(action)) return () => {
      return this.doAction(action)
    }
    let [key, expr] = action.split(':', 2)
    if (!expr || !this.actions.has(key)) throw new Error(`Invalid action ${action}`)
    return () => {
      return this.doAction(key, expr)
    }
  }

  public async doAction(key: string, expr?: string): Promise<void> {
    let fn = this.actions.get(key)
    if (!fn) throw new Error(`Action ${key} doesn't exist`)
    await Promise.resolve(fn(expr))
  }

  private scrollPreview(dir: 'up' | 'down'): void {
    const floatPreview = listConfiguration.get<boolean>('floatPreview', false)
    let { nvim } = this
    nvim.pauseNotification()
    nvim.call('coc#list#scroll_preview', [dir, floatPreview], true)
    nvim.command('redraw', true)
    nvim.resumeNotification(false, true)

View on GitHub (pinned to 50e974d969)

Solutions

  1. Use a registered action name (see :CocList action docs / mappings.actions keys)
  2. Ensure the '<key>:<expr>' form uses a valid action key before the colon and a non-empty expression
  3. Check spelling against the built-in action list (do, quit, toggleSelect, etc.)
  4. Update outdated custom mappings after upgrading coc.nvim

Example fix

// before
mappings.getAction('dd:delete') // 'dd' not a registered key
// after
mappings.getAction('d:delete')  // 'd' is a registered action key
Defensive patterns

Strategy: validation

Validate before calling

function canResolveAction(mappings: ListMappings, action: string): boolean {
  const [key, expr] = action.split(':', 2)
  return (expr === undefined && /* action exists check via try */ true) || (!!expr && action.split(':').length === 2 && !!key)
}
// Prefer: wrap in try/catch since registration set is internal to mappings

Try / catch

let fn
try {
  fn = mappings.getAction(name)
} catch (e) {
  if (String(e.message).startsWith('Invalid action')) {
    console.warn(`Unknown list action '${name}', check coc-list mapping docs`)
    return
  }
  throw e
}

Prevention

When it happens

Trigger: Calling mappings.getAction(name) with a typo, an unregistered action name, a bare 'j:' with no expression, or a 'foo:expr' where 'foo' is not a registered action key.

Common situations: User-defined list mappings in coc-settings.json or list configuration referencing non-existent actions; extension authors wiring custom keybindings with wrong action names; version changes renaming list actions.

Related errors


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