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
- Check plugin.hasAction(key) before calling addAction, or make registration idempotent
- Wrap addAction in try/catch to tolerate duplicate registration on reload
- Choose a unique, extension-prefixed action key (e.g. 'myext.format')
- 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
- Make action registration idempotent with hasAction checks
- Prefix action keys with your extension name to avoid collisions
- Run registration only once per activation lifecycle
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.