neoclide/coc.nvim · error

Error on loadExtension ${res.reason}

Error message

Error on loadExtension ${res.reason}

What it means

loadExtension in src/extension/manager.ts, when given an array of folders, loads them with Promise.allSettled and, if any sub-load rejected, rethrows `Error on loadExtension <reason>`. Only the first rejection is thrown and the remaining results are still iterated; the original rejection reason is embedded as a string, so it is wrapped context rather than the original error object.

Source

Thrown at src/extension/manager.ts:316

    return extension.isActive === true
  }

  public async deactivate(id: string): Promise<void> {
    let item = this.extensions.get(id)
    if (!item || !item.extension.isActive) return
    await Promise.resolve(item.deactivate())
  }

  /**
   * Load extension from folder, folder should contains coc extension.
   */
  public async loadExtension(folder: string | string[], noActive = false): Promise<boolean> {
    if (Array.isArray(folder)) {
      let results = await Promise.allSettled(folder.map(f => {
        return this.loadExtension(f, noActive)
      }))
      results.forEach(res => {
        if (res.status === 'rejected') throw new Error(`Error on loadExtension ${res.reason}`)
      })
      return true
    }
    let errors: string[] = []
    let obj = loadExtensionJson(folder, workspace.version, errors)
    if (errors.length > 0) throw new Error(errors[0])
    let { name } = obj
    if (this.states.isDisabled(name)) return false
    // unload if loaded
    await this.unloadExtension(name)
    let isLocal = !this.states.hasExtension(name)
    if (isLocal) this.states.addLocalExtension(name, folder)
    await this.registerExtension(folder, Object.freeze(obj), isLocal ? ExtensionType.Local : ExtensionType.Global, noActive)
    return true
  }

  /**
   * Deactivate & unregist extension

View on GitHub (pinned to 50e974d969)

Solutions

  1. Read the embedded reason to identify which folder failed, then fix that folder (missing or invalid package.json/extension JSON)
  2. Validate each folder contains a loadable extension manifest before batching
  3. Call loadExtension per folder in a loop with individual try/catch to get precise errors and keep loading the rest
  4. Reinstall or remove the broken extension directory

Example fix

// before
await manager.loadExtension(folders) // one bad folder aborts with wrapped error
// after
for (const f of folders) {
  try { await manager.loadExtension(f) } catch (e) { logger.error(`skip ${f}:`, e) }
}
Defensive patterns

Strategy: try-catch

Validate before calling

const ok = folders.every(f => fs.existsSync(path.join(f, 'package.json')))

Try / catch

try {
  await manager.loadExtension(folders)
} catch (e) {
  if (e.message.startsWith('Error on loadExtension')) {
    logger.error(`one folder failed: ${e.message}`)
  } else throw e
}

Prevention

When it happens

Trigger: Calling loadExtension(['dirA','dirB',...]) where at least one directory fails to load — e.g. missing package.json/extension JSON, invalid JSON (errors from loadExtensionJson), or a nested loadExtension rejection.

Common situations: A folder in coc.extensions or the extension root was deleted/renamed; a broken extension among many installed; passing a file path instead of a folder directory.

Related errors


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