neoclide/coc.nvim · error
method ${method} not found on extension ${id}
Error message
method ${method} not found on extension ${id} What it means
ExtensionManager.call() throws `method <method> not found on extension <id>` when the extension is registered (and activated on demand) but its exports object does not expose a function with the requested method name. The runtime exports contract is checked with typeof exports[method] !== 'function'.
Source
Thrown at src/extension/manager.ts:367
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}`)
}
return await Promise.resolve(exports[method].apply(null, args))
}
public registContribution(id: string, packageJSON: any, directory: string, filepath?: string): void {
let { contributes, activationEvents } = packageJSON
let { configuration, rootPatterns, commands } = contributes ?? {}
let definitions: IStringDictionary<IJSONSchema> | undefined
let props = getProperties(configuration ?? {})
if (!isEmpty(props)) {
// /configuration
let properties = convertProperties(props, ConfigurationScope.WINDOW)
if (Is.objectLiteral(configuration.definitions)) {
let prefix = id.replace(/[^\w]/g, '')
const addPrefix = (obj: object, key: string) => {
if (key == '$ref') {
let val = obj[key]
if (Is.string(val) && val.startsWith('#/definitions/')) {View on GitHub (pinned to 50e974d969)
Solutions
- Check the extension's activate() return value — ensure it returns an object containing the method you call
- Align caller and extension versions: the method may have been renamed/removed — consult the extension's API docs
- Verify exact method name and casing
- If you own the extension, export the method: `return { myMethod: async (...args) => {...} }` from activate()
Example fix
// before (extension side)
exports.activate = async () => { /* returns undefined */ }
// after
exports.activate = async () => ({ run: async () => 'ok' }) Defensive patterns
Strategy: try-catch
Validate before calling
const item = manager.getExtension(id)
if (!item?.isActive) await manager.activate(id)
const exp = item.extension.exports
if (!exp || typeof exp[method] !== 'function') throw new Error(`method ${method} unavailable`) Type guard
function hasMethod(exp: unknown, method: string): exp is Record<string, (...args: unknown[]) => unknown> {
return typeof exp === 'object' && exp !== null &&
typeof (exp as Record<string, unknown>)[method] === 'function'
} Try / catch
try {
return await manager.call(id, method, args)
} catch (e) {
if (/method .* not found on extension/.test(e.message)) {
logger.warn(`API mismatch with ${id}: ${method}`)
return fallbackValue
}
throw e
} Prevention
- Pin compatible extension versions alongside the calling code
- Check the extension's exported API docs before calling new methods
- Ensure activate() always returns the exports object
- Feature-detect methods instead of assuming they exist across versions
When it happens
Trigger: Calling manager.call(id, 'activateX', ...) where the extension's exports lacks activateX, exports is null/undefined despite being active, or the method exists but is not a function.
Common situations: Extension version drift: the caller targets an API method removed/renamed in a newer extension release; extension's activate() returned nothing (exports undefined); passing the wrong method name casing.
Related errors
AI-assisted analysis of neoclide/coc.nvim@50e974d969 (2026-08-31).
Data as JSON: /api/errors/75fc38068d4ad75b.
Report an issue: GitHub.