{"record":{"id":"41a72425a0fd46de","repo":"Hmbown/CodeWhale","slug":"lsp-response-has-no-result","errorCode":null,"errorMessage":"LSP response has no result","messagePattern":"LSP response has no result","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/lsp/client.rs","lineNumber":501,"sourceCode":"        let response = timeout(wait, async {\n            send_message(&self.tx_outbound, &payload).await?;\n            rx.await.map_err(|_| anyhow!(\"LSP request channel closed\"))\n        })\n        .await;\n        self.pending.lock().await.remove(&id);\n        match response {\n            Ok(Ok(reply)) => {\n                if let Some(error) = reply.get(\"error\") {\n                    let message = error\n                        .get(\"message\")\n                        .and_then(Value::as_str)\n                        .unwrap_or(\"LSP request failed\");\n                    return Err(anyhow!(\"{message}\"));\n                }\n                reply\n                    .get(\"result\")\n                    .cloned()\n                    .ok_or_else(|| anyhow!(\"LSP response has no result\"))\n            }\n            Ok(Err(error)) => Err(error),\n            Err(_) => Err(anyhow!(\"LSP request timed out for {method}\")),\n        }\n    }\n\n    async fn shutdown(&self) {\n        let mut child = self.child.lock().await;\n        if let Some(mut c) = child.take() {\n            let _ = c.start_kill();\n            let _ = c.wait().await;\n        }\n        for task in &self.tasks {\n            task.abort();\n        }\n        self.pending.lock().await.clear();\n    }\n}","sourceCodeStart":483,"sourceCodeEnd":519,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/lsp/client.rs#L483-L519","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Fix the server/stub to include a `result` field (JSON null is acceptable) in every response","Log the raw reply frame to confirm what the server actually sent","Check for framing/parsing bugs between the server and this client that could truncate the payload","If the server legitimately returns null, encode it as `{\"result\": null}` not an absent field"],"exampleFix":"// before (stub reply)\njson!({\"id\": 1, \"jsonrpc\": \"2.0\"})\n// after\njson!({\"id\": 1, \"jsonrpc\": \"2.0\", \"result\": null})","handlingStrategy":"validation","validationCode":"// validate the stub/server reply shape before treating it as a response\nfn is_valid_jsonrpc_reply(reply: &Value) -> bool {\n    reply.get(\"result\").is_some() || reply.get(\"error\").is_some()\n}","typeGuard":"fn has_result(reply: &serde_json::Value) -> Option<&serde_json::Value> {\n    if reply.get(\"error\").is_none() && reply.get(\"result\").is_some() {\n        reply.get(\"result\")\n    } else {\n        None\n    }\n}","tryCatchPattern":"match client.request(method, params, wait).await {\n    Ok(reply) => reply,\n    Err(e) if e.to_string() == \"LSP response has no result\" => {\n        // malformed server reply: log raw frame, fall back to empty result\n        log_raw_frame(method);\n        Ok(Value::Null)\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Ensure test stubs always include a `result` (null counts) or `error` field","Conform to JSON-RPC 2.0 framing in any custom server","Log raw inbound frames to catch truncation/misparsing upstream","Avoid middleware that can strip response fields"],"tags":["lsp","jsonrpc","malformed-response"],"backgroundTag":"unexpected-response-shape","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}