Hmbown/CodeWhale · error

LSP response has no result

Error message

LSP response has no result

What it means

The JSON-RPC response contained neither an `error` nor a `result` field. A valid JSON-RPC reply must carry one of the two, so the library treats a bare response as a malformed reply and errors rather than returning null to the caller.

Solutions

  1. Fix the server/stub to include a `result` field (JSON null is acceptable) in every response
  2. Log the raw reply frame to confirm what the server actually sent
  3. Check for framing/parsing bugs between the server and this client that could truncate the payload
  4. If the server legitimately returns null, encode it as `{"result": null}` not an absent field

Example fix

// before (stub reply)
json!({"id": 1, "jsonrpc": "2.0"})
// after
json!({"id": 1, "jsonrpc": "2.0", "result": null})
Defensive patterns

Strategy: validation

Validate before calling

// validate the stub/server reply shape before treating it as a response
fn is_valid_jsonrpc_reply(reply: &Value) -> bool {
    reply.get("result").is_some() || reply.get("error").is_some()
}

Type guard

fn has_result(reply: &serde_json::Value) -> Option<&serde_json::Value> {
    if reply.get("error").is_none() && reply.get("result").is_some() {
        reply.get("result")
    } else {
        None
    }
}

Try / catch

match client.request(method, params, wait).await {
    Ok(reply) => reply,
    Err(e) if e.to_string() == "LSP response has no result" => {
        // malformed server reply: log raw frame, fall back to empty result
        log_raw_frame(method);
        Ok(Value::Null)
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A non-conformant server sends a response missing both fields; a reply frame got corrupted or mis-parsed upstream so only metadata survived; forwarding proxies/middleware stripped the result.

Common situations: Custom or in-development language servers with incomplete JSON-RPC framing; tests using hand-rolled stub replies; intermediate serialization layers dropping null-ish results incorrectly.

Related errors


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

Appendix: source

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

        let response = timeout(wait, async {
            send_message(&self.tx_outbound, &payload).await?;
            rx.await.map_err(|_| anyhow!("LSP request channel closed"))
        })
        .await;
        self.pending.lock().await.remove(&id);
        match response {
            Ok(Ok(reply)) => {
                if let Some(error) = reply.get("error") {
                    let message = error
                        .get("message")
                        .and_then(Value::as_str)
                        .unwrap_or("LSP request failed");
                    return Err(anyhow!("{message}"));
                }
                reply
                    .get("result")
                    .cloned()
                    .ok_or_else(|| anyhow!("LSP response has no result"))
            }
            Ok(Err(error)) => Err(error),
            Err(_) => 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;
        }
        for task in &self.tasks {
            task.abort();
        }
        self.pending.lock().await.clear();
    }
}

View on GitHub (pinned to 73e0f67d83)