Hmbown/CodeWhale · error

LSP initialize response is missing server capabilities

Error message

LSP initialize response is missing server capabilities

What it means

After sending the `initialize` request, spawn_with_timeout requires the response to contain an object under `capabilities`. A server that omits it is non-conformant or answered with something unexpected, so startup is aborted.

Solutions

  1. Log the full initialize response to see what actually came back
  2. Verify the configured server command is a real LSP server at a supported version
  3. Check whether the initialize call returned a JSON-RPC error and surface that instead
  4. Update or replace the LSP server

Example fix

// before
if !result.get("capabilities").is_some_and(Value::is_object) {
    return Err(anyhow!("LSP initialize response is missing server capabilities"));
}
// after
if let Some(err) = result.get("error") {
    return Err(anyhow!("LSP initialization failed: {err}"));
}
if !result.get("capabilities").is_some_and(Value::is_object) {
    return Err(anyhow!("LSP initialize response is missing server capabilities: {result}"));
}
Defensive patterns

Strategy: try-catch

Validate before calling

const r = await initializeOnce();
if (!(r && typeof r === 'object' && r.capabilities && typeof r.capabilities === 'object')) throw new Error('non-conformant LSP server');

Type guard

fn has_capabilities(v: &Value) -> bool { v.get("capabilities").map(|c| c.is_object()).unwrap_or(false) }

Try / catch

match spawn_with_timeout(...).await {
    Err(e) if e.to_string().contains("missing server capabilities") => {
        eprintln!("server not LSP-conformant; check command and version");
    }
    other => other,
}

Prevention

When it happens

Trigger: `spawn_with_timeout` receiving an initialize reply without a `capabilities` object — e.g. the server sent an error response, a notification instead of a reply, or is an old/non-conformant LSP server.

Common situations: Pointing the client at a binary that is not a real LSP server; server crashes during initialize and an error object is returned; protocol version mismatch.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/76026a2d350842ec. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/lsp/client.rs:288

            diagnostics_rx: AsyncMutex::new(rx_diag),
            pending,
            next_id: AsyncMutex::new(1),
            language_id: language_id.to_string(),
            opened: AsyncMutex::new(HashMap::new()),
        };
        let result = transport.request("initialize", json!({
            "processId": std::process::id(),
            "rootUri": uri_from_path(&workspace),
            "capabilities": {
                "general": { "positionEncodings": ["utf-16"] },
                "textDocument": {
                    "publishDiagnostics": { "relatedInformation": false, "versionSupport": true }
                }
            },
            "workspaceFolders": [{"uri": uri_from_path(&workspace), "name": "workspace"}]
        }), initialize_wait).await.context("LSP initialization failed")?;
        if !result.get("capabilities").is_some_and(Value::is_object) {
            return Err(anyhow!(
                "LSP initialize response is missing server capabilities"
            ));
        }
        if result
            .pointer("/capabilities/positionEncoding")
            .is_some_and(|encoding| encoding.as_str() != Some("utf-16"))
        {
            return Err(anyhow!("LSP server must use UTF-16 positions"));
        }
        timeout(
            initialize_wait,
            send_message(
                &transport.tx_outbound,
                &json!({
                    "jsonrpc": "2.0", "method": "initialized", "params": {}
                }),
            ),
        )

View on GitHub (pinned to 73e0f67d83)