neoclide/coc.nvim · error
Extension ${id} not registered
Error message
Extension ${id} not registered What it means
reloadExtension in src/extension/manager.ts throws `Extension <id> not registered` when there is no registry entry for the id, or when the entry is an Internal extension. Internal (built-in) extensions cannot be reloaded from disk, and an unknown id has nothing to reload, so both cases are rejected up front.
Source
Thrown at src/extension/manager.ts:349
}
/**
* Deactivate & unregist extension
*/
public async unloadExtension(id: string): Promise<void> {
let item = this.extensions.get(id)
if (item) {
await this.deactivate(id)
this.extensions.delete(id)
this._onDidUnloadExtension.fire(id)
}
disposeExtension(id)
}
public async reloadExtension(id: string): Promise<void> {
let item = this.extensions.get(id)
if (!item || item.type == ExtensionType.Internal) {
throw new Error(`Extension ${id} not registered`)
}
if (item.type == ExtensionType.SingleFile) {
await this.loadExtensionFile(item.filepath)
} else {
await this.loadExtension(item.directory)
}
}
public async call(id: string, method: string, args: any[]): Promise<any> {
let item = this.extensions.get(id)
if (!item) throw new Error(`extension ${id} not registered`)
let { extension } = item
if (!extension.isActive) {
await this.activate(id)
}
let { exports } = extension
if (!exports || typeof exports[method] !== 'function') {
throw new Error(`method ${method} not found on extension ${id}`)View on GitHub (pinned to 50e974d969)
Solutions
- Confirm the id is registered (getExtension(id) !== undefined) and not internal before reloading
- If the extension was unloaded intentionally, ignore or dispose the stale watcher instead of reloading
- Reload via the correct path: loadExtension(directory) for folder extensions or loadExtensionFile for single-file ones
- For internal extensions, restart the coc server instead of hot-reloading
Example fix
// before await manager.reloadExtension(id) // id may be stale/internal // after const item = manager.getExtension(id) if (item && item.type !== ExtensionType.Internal) await manager.reloadExtension(id)
Defensive patterns
Strategy: validation
Validate before calling
const item = manager.getExtension(id) if (!item || item.type === 'Internal') return // cannot reload
Try / catch
try {
await manager.reloadExtension(id)
} catch (e) {
if (/not registered$/.test(e.message)) {
logger.warn(`cannot reload ${id}: not reloadable`)
} else throw e
} Prevention
- Dispose watchers when an extension is unloaded or disabled
- Never attempt to hot-reload internal extensions — restart the server instead
- Verify registration and type before reload calls
- Guard file-watch callbacks against stale ids
When it happens
Trigger: watchExtension's file/watchman callback firing reloadExtension(id) after the extension was unregistered or unloaded; calling reloadExtension directly with an unknown id or with an internal extension's id.
Common situations: Editing a watched extension file after the extension was disabled/removed, so the watcher fires on a stale id; attempting to hot-reload a built-in internal extension; typo in the id.
Related errors
- keymap: "${name}" already exists.
- Extension ${id} not registered!
- Client got disposed and can't be restarted.
- Client is currently stopping. Can only restart a full stoppe
- Previous start failed. Can't restart server.
AI-assisted analysis of neoclide/coc.nvim@50e974d969 (2026-08-31).
Data as JSON: /api/errors/64e86a069e6fe68b.
Report an issue: GitHub.