neoclide/coc.nvim · error · Error

Previous start failed. Can't restart server.

Error message

Previous start failed. Can't restart server.

What it means

Thrown by LanguageClient.$start() when the client's state is ClientState.StartFailed, meaning a previous start attempt failed (e.g. the server process crashed on launch) and the library refuses to retry with the same failed client. The failed state is sticky by design to surface the original configuration problem.

Source

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

        reject(error)
      }
    }
    return this._onStart
  }

  public start(): Promise<void> & Disposable {
    let p: any = this._start()
    p.dispose = () => {
      if (this.needsStop()) {
        void this.stop()
      }
    }
    return p
  }

  private async $start(): Promise<Connection> {
    if (this.$state === ClientState.StartFailed) {
      throw new Error(`Previous start failed. Can't restart server.`)
    }
    await this._start()
    const connection = this.activeConnection()
    if (connection === undefined) {
      throw new Error(`Starting server failed`)
    }
    return connection
  }

  private handleConnectionEvents(connection: Connection) {
    connection.onNotification(LogMessageNotification.type, message => {
      switch (message.type) {
        case MessageType.Error:
          this.error(message.message)
          break
        case MessageType.Warning:
          this.warn(message.message)
          break

View on GitHub (pinned to 50e974d969)

Solutions

  1. Fix the root launch failure: check :CocCommand workspace.showOutput for the original spawn/initialization error.
  2. Verify the server executable exists and runs (`<server> --version` in a terminal).
  3. Correct command/args in coc-settings.json or the extension's server options.
  4. Create a new client instance (or :CocRestart) to reset StartFailed state and retry.

Example fix

// before
"languageserver.rust": { "command": "rust-analyer" }  // typo

// after
"languageserver.rust": { "command": "rust-analyzer" }
Defensive patterns

Strategy: try-catch

Validate before calling

// preflight: verify the server command exists before start
import { execFileSync } from 'child_process'
function serverExists(cmd: string): boolean {
  try { execFileSync('which', [cmd]); return true } catch { return false }
}

Try / catch

try {
  await client.start()
} catch (e) {
  if (String(e).includes('Previous start failed')) {
    // fix config, then rebuild a fresh client and retry
    client = createNewClient()
    await client.start()
  }
}

Prevention

When it happens

Trigger: Calling start()/restart after a server failed to launch (bad command path, missing executable, immediate crash, invalid initialization), then invoking any operation that triggers $start again (a request, notification, or restart).

Common situations: Language server command not installed or not on $PATH (typo in coc-settings.json servers/extension config); server binary version incompatible; server exits instantly due to bad args; firewall/permission blocking spawn on Windows.

Related errors


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