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 extensionView on GitHub (pinned to 50e974d969)
Solutions
- Read the embedded reason to identify which folder failed, then fix that folder (missing or invalid package.json/extension JSON)
- Validate each folder contains a loadable extension manifest before batching
- Call loadExtension per folder in a loop with individual try/catch to get precise errors and keep loading the rest
- 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
- Load folders individually when partial failure is acceptable
- Validate each folder has a loadable manifest before batch loading
- Keep extension directories intact — avoid partial deletes/renames
- Log the embedded reason string to find the failing folder
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.