neoclide/coc.nvim · error · Error

Stopping the server timed out

Error message

Stopping the server timed out

What it means

BaseLanguageClient.stop() waits for the server connection to end within a timeout window. If the connection has not been ended when the timeout fires, the client logs 'Stopping server timed out' and throws so callers know shutdown did not complete cleanly. The state is still forced to Stopped in the finally block.

Source

Thrown at src/language-client/client.ts:1381

    })(connection)
    // If the connection closes while the shutdown is in flight (e.g. the
    // server crashed), handleConnectionClosed signals it here so the stop
    // completes successfully: the server is gone, which is the outcome the
    // caller asked for. Without this, the pending shutdown rejects after the
    // connection is disposed, reporting a false stop failure.
    const close = new Promise<Connection>(resolve => {
      this._onStopClose = () => resolve(connection)
    })

    return this._onStop = Promise.race([tp, shutdown, close]).then(connection => {
      if (tm) clearTimeout(tm)
      // The connection won the race with the timeout.
      if (connection !== undefined) {
        connection.end()
        connection.dispose()
      } else {
        this.error(`Stopping server timed out`, undefined)
        throw new Error(`Stopping the server timed out`)
      }
    }, error => {
      this.error(`Stopping server failed`, error)
      throw error
    }).finally(() => {
      this.$state = ClientState.Stopped
      if (mode === 'stop') {
        this.cleanUpChannel()
      }
      this._onStart = undefined
      this._onStop = undefined
      this._onStopClose = undefined
      this._connection = undefined
      this._ignoredRegistrations.clear()
    })
  }

  public dispose(timeout = 2000): Promise<void> {

View on GitHub (pinned to 50e974d969)

Solutions

  1. Check the server implementation responds to the shutdown/exit requests promptly
  2. Increase the shutdown timeout passed to the client constructor options
  3. Kill leftover server processes manually and retry stopping
  4. Update or replace the misbehaving language server

Example fix

// before
await client.stop()
// after
try {
  await client.stop()
} catch (e) {
  // server ignored shutdown; state is already Stopped
  console.warn('Server did not shut down cleanly:', e)
}
Defensive patterns

Strategy: try-catch

Validate before calling

// No pre-call validation; ensure server supports shutdown before stop
// e.g. check capabilities negotiated during initialize contain shutdown support

Try / catch

try {
  await client.stop()
} catch (e) {
  if (String(e.message).includes('Stopping the server timed out')) {
    // force-kill leftover server process; client state is already Stopped
  } else { throw e }
}

Prevention

When it happens

Trigger: Calling client.stop() (or extension deactivate) while the language server process hangs, ignores the shutdown request, or takes longer than the shutdown timeout (default 1s, configurable via a requestTimeout/shutdown timeout option).

Common situations: A server that never responds to the LSP 'shutdown' request, a server blocked on I/O or a deadlock, slow teardown on Windows where process kill is asynchronous, or an extension deactivating while a request is still in flight.

Understand the failure class

Related errors


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