Hmbown/CodeWhale · error
{message}
Error message
{message} What it means
The LSP client received a JSON-RPC reply carrying an error object and converts it into an error using the server's message field (falling back to 'LSP request failed' when the field is missing or not a string). The text is whatever the language server chose: unsupported method, invalid params, or a server-internal failure. This is a protocol-level error delivered per request, not a transport failure.
Source
Thrown at crates/tui/src/lsp/client.rs:325
let payload = json!({
"jsonrpc": "2.0",
"id": id,
"method": method,
"params": params,
});
if let Err(err) = send_message(&self.tx_outbound, &payload).await {
let mut pending = self.pending.lock().await;
pending.remove(&id);
return Err(err);
}
match timeout(wait, rx).await {
Ok(Ok(reply)) => {
if let Some(error) = reply.get("error") {
let message = error
.get("message")
.and_then(|v| v.as_str())
.unwrap_or("LSP request failed");
return Err(anyhow!("{message}"));
}
Ok(reply.get("result").cloned().unwrap_or(Value::Null))
}
Ok(Err(_)) => Err(anyhow!("LSP request channel closed")),
Err(_) => {
let mut pending = self.pending.lock().await;
pending.remove(&id);
Err(anyhow!("LSP request timed out for {method}"))
}
}
}
async fn shutdown(&self) {
let mut child = self.child.lock().await;
if let Some(mut c) = child.take() {
let _ = c.start_kill();
let _ = c.wait().await;
}View on GitHub (pinned to 8880682c63)
Solutions
- Read the message text; it names the server-side cause (method not found, invalid params, internal error)
- Gate optional calls on the capabilities the server returned in its initialize result
- Ensure documents are opened and synced (didOpen/didChange) before querying them
- Update or restart the language server if it reports internal errors
Defensive patterns
Strategy: try-catch
Validate before calling
// Only call optional methods the server advertised in its initialize result
fn supports(server_caps: &serde_json::Value, method: &str) -> bool {
let on = |ptr: &str| server_caps.pointer(ptr).and_then(|v| v.as_bool()).unwrap_or(false);
match method {
"textDocument/hover" => on("/capabilities/hoverProvider"),
"textDocument/rename" => on("/capabilities/renameProvider"),
"textDocument/formatting" => on("/capabilities/documentFormattingProvider"),
_ => true,
}
} Try / catch
// anyhow carries the server's message; branch on its content
if let Err(err) = client.request("textDocument/hover", params).await {
let msg = err.to_string();
if msg.contains("not supported") || msg.contains("Unhandled method") || msg.contains("unknown method") {
// capability gap: degrade gracefully
} else {
return Err(err);
}
} Prevention
- Gate optional requests on advertised capabilities
- Complete the initialize handshake before any other request
- Keep didOpen/didChange in sync before querying documents
- Capture server logs beside client logs to correlate JSON-RPC error codes
When it happens
Trigger: Requests such as textDocument/hover, definition, or rename against a server that does not advertise or implement the method; params referencing a document the server has not seen (no didOpen); stale document versions after rapid edits; requests issued before initialization completes.
Common situations: Calling optional methods on minimal servers, skipping didOpen so the server rejects unknown files, version drift between editor and server buffers, older server builds with different capability surfaces.
Related errors
- LSP request timed out for {method}
- MCP error in '{method}': {error}
- MCP error in '{}': {}
- ${detail || ("HTTP " + res.status)}
- No active turn
AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16).
Data as JSON: /api/errors/d8dbf95718d19c3f.
Report an issue: GitHub.