neoclide/coc.nvim · error · Error

Action ${key} doesn't exist

Error message

Action ${key} doesn't exist

What it means

doAction looks up the handler for the given action key in the registered actions map; if absent it throws. Unlike getAction, this is reached when doAction is invoked directly (or via a previously valid mapping whose action was removed), meaning no handler exists for that key.

Source

Thrown at src/list/mappings.ts:306

  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. Verify the action key exists with mappings.hasAction / the registered actions list
  2. Catch the error and fall back to a default action or notify the user
  3. Update bindings after upgrading coc.nvim if action names changed
  4. Register the custom action before dispatching to it

Example fix

// before
await mappings.doAction('refreshx') // typo
// after
if (mappings.hasAction('refresh')) await mappings.doAction('refresh')
Defensive patterns

Strategy: validation

Validate before calling

// Check action existence before dispatch (getAction throws for unknown keys too)
let handler
try { handler = mappings.getAction(key) } catch { handler = null }
if (!handler) console.warn(`Action '${key}' is not registered`)

Try / catch

try {
  await mappings.doAction(key, expr)
} catch (e) {
  if (String(e.message).includes("doesn't exist")) {
    console.warn(`List action '${key}' missing; was the list extension unloaded?`)
    return
  }
  throw e
}

Prevention

When it happens

Trigger: Calling mappings.doAction(key) with a key never registered in the actions Map, or an expression dispatched to a key that was unregistered (e.g. by a list extension disposing its mappings).

Common situations: Custom list keymappings bound to actions of a list that failed to load; API consumers invoking doAction with internal action names that changed between versions; typos in programmatic dispatch.

Related errors


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