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

  1. Read the message text; it names the server-side cause (method not found, invalid params, internal error)
  2. Gate optional calls on the capabilities the server returned in its initialize result
  3. Ensure documents are opened and synced (didOpen/didChange) before querying them
  4. 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

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


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/d8dbf95718d19c3f. Report an issue: GitHub.