neoclide/coc.nvim · error

Service ${id} not found

Error message

Service ${id} not found

What it means

Services toggle throws when the given id has never been registered with the service manager. coc.nvim keeps registered services in a map and looks the id up before toggling its state; an unknown id means there is nothing to start or stop. It is a fail-fast guard against typos or unregistered service ids.

Source

Thrown at src/services.ts:233

    if (service) return Promise.resolve(service.stop())
  }

  /**
   * @internal
   * Best-effort stop of all registered services, used on process exit.
   * Stops waiting after `timeout` milliseconds.
   */
  public stopAll(timeout = 3000): Promise<void> {
    let all = Array.from(this.registered.values())
    return Promise.race([
      Promise.allSettled(all.map(s => Promise.resolve(s.stop()))).then(() => undefined),
      wait(timeout)
    ])
  }

  public async toggle(id: string): Promise<void> {
    let service = this.registered.get(id)
    if (!service) throw new Error(`Service ${id} not found`)
    let { state } = service
    if (state == ServiceStat.Running) {
      await Promise.resolve(service.stop())
    } else if (state == ServiceStat.Initial || state == ServiceStat.StartFailed) {
      await service.start()
    } else if (state == ServiceStat.Stopped) {
      await service.restart()
    }
  }
  /**
   * @internal
   */

  public getServiceStats(): ServiceInfo[] {
    let res: ServiceInfo[] = []
    for (let [id, service] of this.registered) {
      res.push({
        id,

View on GitHub (pinned to 50e974d969)

Solutions

  1. Verify the service id by listing registered services (check how extensions register them, e.g. package.json contributes or extension source).
  2. Fix the id string in your toggle call.
  3. Ensure the extension providing the service is activated before toggling.
  4. Check the service was not unregistered/disposed earlier in your code path.

Example fix

// before
await services.toggle('lua-ls')
// after
await services.toggle('lua') // use the exact id passed to registerService
Defensive patterns

Strategy: validation

Validate before calling

let service = services.getService(id)
if (!service) throw new Error(`Unknown service id: ${id}`)
await services.toggle(id)

Type guard

function hasService(id: string): boolean {
  return services.getService(id) != null
}

Try / catch

try {
  await services.toggle(id)
} catch (e) {
  if (String(e.message).includes('not found')) logger.warn(`service ${id} missing`)
}

Prevention

When it happens

Trigger: Calling services.toggle(id) with an id that was never registered via registerService, or after the service was unregistered/disposed.

Common situations: Typo in service id in a custom extension or keymapping; service unregistered on extension deactivate before a delayed toggle call runs.

Related errors


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