neoclide/coc.nvim · error · Error

Invalid engines field

Error message

Invalid engines field

What it means

Thrown by loadGlobalJsonAsync when an extension's package.json either has no `engines` field or lacks both `engines.coc` and `engines.vscode` strings. coc.nvim uses engines to verify compatibility, so a manifest without it is considered invalid.

Source

Thrown at src/extension/stat.ts:279

export function validExtensionFolder(folder: string, version: string): boolean {
  let errors: string[] = []
  let res = loadExtensionJson(folder, version, errors)
  return res != null && errors.length == 0
}

function getEntryFile(main: string | undefined): string {
  if (!main) return 'index.js'
  if (!main.endsWith('.js')) return main + '.js'
  return main
}

export async function loadGlobalJsonAsync(folder: string, version: string): Promise<ExtensionJson> {
  let jsonFile = path.join(folder, 'package.json')
  let content = await readFile(jsonFile, 'utf8')
  let packageJSON = JSON.parse(content) as ExtensionJson
  let { engines } = packageJSON
  let main = getEntryFile(packageJSON.main)
  if (!engines || (typeof engines.coc !== 'string' && typeof engines.vscode !== 'string')) throw new Error('Invalid engines field')
  let keys = Object.keys(engines)
  if (keys.includes('coc') && !semver.satisfies(version, engines['coc'].replace(/^\^/, '>='))) {
    throw new Error(`coc.nvim version not match, required ${engines['coc']}`)
  }
  if (!engines.vscode && !fs.existsSync(path.join(folder, main))) {
    throw new Error(`main file ${main} not found, you may need to build the project.`)
  }
  return packageJSON
}

export function loadExtensionJson(folder: string, version: string, errors: string[]): ExtensionJson | undefined {
  let jsonFile = path.join(folder, 'package.json')
  if (!fs.existsSync(jsonFile)) {
    errors.push(`package.json not found in ${folder}`)
    return undefined
  }
  let packageJSON = loadJson(jsonFile) as ExtensionJson
  let { name, engines } = packageJSON

View on GitHub (pinned to 50e974d969)

Solutions

  1. Add `"engines": { "coc": ">= 0.0.80" }` (or a vscode engine) to the extension's package.json
  2. Ensure you are loading an actual coc extension, not an arbitrary npm package
  3. Reinstall the extension from a proper release

Example fix

// before (package.json)
{ "name": "my-ext", "main": "lib/index.js" }
// after
{ "name": "my-ext", "main": "lib/index.js", "engines": { "coc": ">=0.0.80" } }
Defensive patterns

Strategy: validation

Validate before calling

const pkg = JSON.parse(fs.readFileSync(path.join(folder, 'package.json'), 'utf8'));
if (!pkg.engines || (typeof pkg.engines.coc !== 'string' && typeof pkg.engines.vscode !== 'string')) {
  throw new Error('extension package.json lacks valid engines');
}

Try / catch

try {
  await installOrLoad(folder);
} catch (e) {
  if (e.message === 'Invalid engines field') {
    console.error(`${folder} is not a valid coc extension (no engines.coc/vscode)`);
  } else throw e;
}

Prevention

When it happens

Trigger: Installing/loading a global extension folder whose package.json has no engines field, or engines missing both coc and vscode entries; malformed hand-written package.json.

Common situations: Locally developed extensions missing engines; copied/vendored packages that are not coc extensions; npm packages accidentally installed into the extension root.

Related errors


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