neoclide/coc.nvim · error

Action ${key} already exists

Error message

Action ${key} already exists

What it means

Plugin.addAction() registers a Vim-callable action in an internal Map keyed by name (plus optional alias). It refuses to overwrite an existing key and throws this error, protecting against accidental action replacement.

Source

Thrown at src/plugin.ts:218

    this.addAction('nextEditAvailable', () => this.handler.nextEdit.available())
    this.addAction('notificationHistory', () => window.notifications.history)
  }

  public get workspace(): Workspace {
    return workspace
  }

  public get window(): Window {
    return window
  }

  public get completion(): Completion {
    return completion
  }

  public addAction(key: string, fn: Callback, alias?: string): void {
    if (this.actions.has(key)) {
      throw new Error(`Action ${key} already exists`)
    }
    this.actions.set(key, fn)
    if (alias) this.actions.set(alias, fn)
  }

  public async init(rtp: string, mcpStarted = false): Promise<void> {
    if (this.initialized) return
    this.initialized = true
    let { nvim } = this
    await extensions.init(rtp)
    await workspace.init(window)
    nvim.setVar('coc_workspace_initialized', true, true)
    snippetManager.init()
    services.init()
    sources.init()
    languages.sources = sources
    completion.init()
    diagnosticManager.init()

View on GitHub (pinned to 50e974d969)

Solutions

  1. Check plugin.hasAction(key) before calling addAction, or make registration idempotent
  2. Wrap addAction in try/catch to tolerate duplicate registration on reload
  3. Choose a unique, extension-prefixed action key (e.g. 'myext.format')
  4. Ensure the registration code runs only once per plugin lifecycle

Example fix

// before
plugin.addAction('myAction', handler) // throws on reload
// after
if (!plugin.hasAction('myAction')) plugin.addAction('myAction', handler)
Defensive patterns

Strategy: validation

Validate before calling

if (plugin.hasAction('myAction')) return
plugin.addAction('myAction', handler)

Try / catch

try {
  plugin.addAction('myAction', handler)
} catch (e) {
  if (e.message.includes('already exists')) {
    // already registered (e.g. after reload); safe to ignore
  }
}

Prevention

When it happens

Trigger: Calling plugin.addAction('myAction', fn) (or an alias) when 'myAction' is already registered — e.g. registering the same action twice during init/reload, or picking a key that collides with a built-in action like 'symbol' or 'definition'.

Common situations: Extensions registering actions on every activation without idempotency (coc restarts or extension reload re-runs registration); two extensions choosing the same action name; re-sourcing a config that calls addAction again.

Related errors


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