neoclide/coc.nvim · error

Extension ${id} not registered!

Error message

Extension ${id} not registered!

What it means

activate()/activateWithSet in src/extension/manager.ts throws when the requested extension id has no entry in the ExtensionManager registry. Activation can only proceed for extensions previously loaded/registered (internal, single-file, or loaded from a folder). A missing entry is treated as a hard programming/state error rather than a soft 'not active' result.

Source

Thrown at src/extension/manager.ts:270

  public get loadedExtensions(): string[] {
    return Array.from(this.extensions.keys())
  }

  public get all(): Extension<API>[] {
    return Array.from(this.extensions.values()).map(o => o.extension)
  }

  /**
   * Activate extension, throw error if disabled or doesn't exist.
   * Returns true if extension successfully activated.
   */
  public async activate(id: string): Promise<boolean> {
    return this.activateWithSet(id, new Set())
  }

  private async activateWithSet(id: string, activating: Set<string>): Promise<boolean> {
    let item = this.extensions.get(id)
    if (!item) throw new Error(`Extension ${id} not registered!`)
    let { extension } = item
    if (extension.isActive) return true
    if (activating.has(id)) {
      logger.warn(`Circular dependency detected: ${id}`)
      return false
    }
    activating.add(id)
    const { packageJSON } = extension
    if (packageJSON.extensionDependencies?.length > 0) {
      const deps = packageJSON.extensionDependencies
      const results = await Promise.allSettled(deps.map(dep => this.activateWithSet(dep, activating)))
      for (let i = 0; i < results.length; i++) {
        const result = results[i]
        if (result.status === 'rejected' || (result.status === 'fulfilled' && !result.value)) {
          const dep = deps[i]
          const reason = result.status === 'rejected' ? result.reason : undefined
          if (reason !== undefined) {
            logger.error(`Could not activate dependency ${dep} for ${id}.`, reason)

View on GitHub (pinned to 50e974d969)

Solutions

  1. Verify the exact id: check the registered ids (e.g. via extension list / package.json `name`) and fix the caller's id string
  2. Ensure the extension is loaded before activating: call loadExtension/loadExtensionFile for the folder or file first
  3. Check whether the extension was disabled via coc.extensions configuration and re-enable it
  4. If activating from an event handler, guard with a registry lookup (getExtension(id)) before calling activate

Example fix

// before
await extensionManager.activate('coc-tsservers') // typo
// after
if (extensionManager.getExtension('coc-tsserver')) {
  await extensionManager.activate('coc-tsserver')
}
Defensive patterns

Strategy: validation

Validate before calling

if (!manager.getExtension(id)) {
  logger.warn(`skip activate: ${id} not registered`)
  return false
}

Try / catch

try {
  await manager.activate(id)
} catch (e) {
  if (/not registered!?$/.test(e.message)) {
    logger.warn(`extension ${id} unavailable:`, e.message)
  } else throw e
}

Prevention

When it happens

Trigger: Calling activate(id) (e.g. via workspace.activateExtension flow or an activation event) with an id that was never loaded, was unloaded/unregistered, or is misspelled; racing an unload that removed the map entry before activation.

Common situations: Typo in the extension id in activation events or coc-settings; extension disabled/removed but still referenced by a keybinding or language trigger; calling activate after unloadExtension; extension failed to load earlier so it was never registered.

Related errors


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