neoclide/coc.nvim · error · Error
Unable to load extension at ${extensionRoot}, missing packag
Error message
Unable to load extension at ${extensionRoot}, missing package.json What it means
Thrown by ExtensionManager.load() when loading a source-code extension whose root folder has no readable package.json, or the parsed JSON has no `name` field. coc.nvim requires a package.json manifest to identify and register an extension. It indicates the given extensionRoot does not contain a valid extension.
Source
Thrown at src/extension/manager.ts:655
void window.showInformationMessage(`watching ${item.directory}`)
client.subscribe('**/*.js', async () => {
this.reloadExtension(id).then(() => {
void window.showInformationMessage(`reloaded ${id}`)
}, onUnexpectedError)
})
}
}
/**
* load extension in folder or file
*/
public async load(filepath: string, active: boolean, options?: ExtensionLoadOptions): Promise<ExportExtension> {
let name: string
if (options?.sourceCode) {
let extensionRoot = options.extensionRoot ?? filepath
let obj = loadJson(path.join(extensionRoot, 'package.json')) as any
name = obj.name
if (!name) throw new Error(`Unable to load extension at ${extensionRoot}, missing package.json`)
await this.unloadExtension(name)
await this.registerExtension(extensionRoot, obj, ExtensionType.Local, true, options)
} else if (isDirectory(filepath)) {
let obj = loadJson(path.join(filepath, 'package.json')) as any
name = obj.name
await this.loadExtension(filepath, true)
} else {
name = await this.loadExtensionFile(filepath, true)
}
if (!name) throw new Error(`Unable to load extension at ${filepath}`)
let disabled = this.states.isDisabled(name)
if (disabled) throw new Error(`extension ${name} is disabled`)
let item = this.getExtension(name)
if (active) await this.activate(name)
return {
get isActive() {
return item.extension.isActive
},View on GitHub (pinned to 50e974d969)
Solutions
- Ensure extensionRoot points to the directory containing a valid package.json with a `name` field
- Verify package.json parses as valid JSON (`cat package.json | node -e 'JSON.parse(require("fs").readFileSync(0))'`)
- Add or fix the `name` field in package.json
- Check the path exists and is the extension root, not a subfolder
Example fix
// before
await coc.extensions.load('/path/to/ext/index.js', true, { sourceCode: true })
// after
await coc.extensions.load('/path/to/ext', true, { sourceCode: true }) // dir containing package.json Defensive patterns
Strategy: validation
Validate before calling
const fs = require('fs');
const root = options?.extensionRoot ?? filepath;
const pkgPath = require('path').join(root, 'package.json');
if (!fs.existsSync(pkgPath)) throw new Error(`No package.json at ${root}`);
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
if (!pkg.name) throw new Error(`package.json at ${root} has no name`); Try / catch
try {
await coc.extensions.load(filepath, true, { sourceCode: true });
} catch (e) {
if (String(e.message).includes('missing package.json')) {
// fall back or prompt user to fix extension root
} else throw e;
} Prevention
- Always pass the extension root directory (containing package.json), not an entry file
- Validate package.json name field before load
- Run JSON.parse validation in CI for local extensions
When it happens
Trigger: Calling coc.extensions.load(filepath, active, {sourceCode: true}) where options.extensionRoot (default filepath) is a directory without package.json, or the package.json lacks a `name` field, or JSON.parse fails silently returning an object without name.
Common situations: Pointing load() at the source file instead of the project root; loading an extension folder that was never built/cloned fully; a malformed package.json; typo'd extensionRoot path.
Related errors
- Unable to load extension at ${filepath}
- extension ${name} is disabled
- Invalid engines field
- Required root pattern not resolved.
- Unexpected messageDialogKind: ${this.messageDialogKind}
AI-assisted analysis of neoclide/coc.nvim@50e974d969 (2026-08-31).
Data as JSON: /api/errors/7b6f5fe68afeaa35.
Report an issue: GitHub.