neoclide/coc.nvim · error

Language server ${id} not found

Error message

Language server ${id} not found

What it means

getLanguageClient resolves the LanguageClient backing a language service. If the service is still missing after waiting 100ms for extension activation, or exists but has no client yet, it throws. This usually means the language server was never registered or is still initializing.

Source

Thrown at src/services.ts:275

  }

  private registerClientsByConfig(lspConfig: { [key: string]: LanguageServerConfig }, folder?: URI): void {
    for (let key of Object.keys(toObject(lspConfig))) {
      let config: LanguageServerConfig = lspConfig[key]
      if (!isValidServerConfig(key, config)) {
        continue
      }
      this.registerLanguageClient(key, config, folder)
    }
  }

  private async getLanguageClient(id: string): Promise<LanguageClient> {
    let service = this.getService(id)
    // wait for extension activate
    if (!service) await wait(100)
    service = this.getService(id)
    if (!service || !service.client) {
      throw new Error(`Language server ${id} not found`)
    }
    return service.client
  }
  /**
   * @internal
   */

  public async sendNotification(id: string, method: string, params?: any): Promise<void> {
    let client = await this.getLanguageClient(id)
    await Promise.resolve(client.sendNotification(method, params))
  }
  /**
   * @internal
   */

  public async sendRequest(id: string, method: string, params?: any, token?: CancellationToken): Promise<any> {
    let client = await this.getLanguageClient(id)
    token = token ?? CancellationToken.None

View on GitHub (pinned to 50e974d969)

Solutions

  1. Confirm the id matches a registered language service.
  2. Wait for service state to become Running before requesting the client (poll state or listen to service events).
  3. Check the language extension is installed and activated for the buffer's filetype.
  4. Inspect service.start failure logs if the client never attaches.

Example fix

// before
let client = await services.getLanguageClient('tsserver')
// after
let service = services.getService('tsserver')
if (!service || service.state !== ServiceStat.Running) return
let client = await services.getLanguageClient('tsserver')
Defensive patterns

Strategy: retry

Validate before calling

let service = services.getService(id)
if (!service || service.state !== ServiceStat.Running) return null

Type guard

function hasClient(id: string): boolean {
  let s = services.getService(id)
  return s != null && s.client != null
}

Try / catch

try {
  return await services.getLanguageClient(id)
} catch (e) {
  logger.warn(`client for ${id} unavailable: ${e.message}`)
  return null
}

Prevention

When it happens

Trigger: Calling services.getLanguageClient(id) (or the client accessor) before the language extension activates, or for a service created without a client, or with a wrong id.

Common situations: Vimrc/autocmd triggers a request on FileType before coc completes extension activation; server failed to spawn leaving service without a client.

Related errors


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