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
- Log the full initialize response to see what actually came back
- Verify the configured server command is a real LSP server at a supported version
- Check whether the initialize call returned a JSON-RPC error and surface that instead
- 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
- Validate the server command resolves to a real LSP binary at startup
- Include the raw response in the error context for diagnosis
- Pin supported server versions
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
- duplicate LSP Content-Length
- LSP frame exceeds size limit or is empty
- LSP header exceeds size limit
- Codewhale stream-json contained an unknown event type
- {err}
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)