{"record":{"id":"97141d6ff4a8ab21","repo":"Hmbown/CodeWhale","slug":"lsp-request-channel-closed","errorCode":null,"errorMessage":"LSP request channel closed","messagePattern":"LSP request channel closed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/lsp/client.rs","lineNumber":485,"sourceCode":"            let id = *next;\n            *next = next.saturating_add(1);\n            id\n        };\n        let (tx, rx) = oneshot::channel();\n        {\n            let mut pending = self.pending.lock().await;\n            pending.insert(id, tx);\n        }\n        let payload = json!({\n            \"jsonrpc\": \"2.0\",\n            \"id\": id,\n            \"method\": method,\n            \"params\": params,\n        });\n        // The deadline includes queue backpressure, not just the reply.\n        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),","sourceCodeStart":467,"sourceCodeEnd":503,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/lsp/client.rs#L467-L503","documentation":"request registers a oneshot reply channel in the pending map, writes the JSON-RPC request to the server's stdin, and awaits the reply. This error means the reply channel's sender was dropped before a response arrived — the server-side reader/dispatch task ended (or the client is shutting down) while this request was in flight.","triggerScenarios":"Language-server process exited so the reader task that resolves pending ids terminated; client shutdown dropped all pending senders; the reader task panicked or was aborted while requests were outstanding.","commonSituations":"LSP binary crashed mid-session (OOM, panic in server); server killed by shutdown while a hover/completion request was pending; misconfigured command that dies after start.","solutions":["Verify the language-server process is alive (check exit status / stderr) and restart the client if it died","Avoid issuing requests while the client is shutting down; check a healthy/ready flag first","Capture server stderr logs to find why the reader task ended","Retry the request after reinitialization"],"exampleFix":"// before\nlet reply = client.request(\"textDocument/hover\", params, wait).await?;\n// after\nif client.is_shutdown() {\n    anyhow::bail!(\"LSP client shut down; reinitialize before requesting\");\n}\nlet reply = client.request(\"textDocument/hover\", params, wait).await?;","handlingStrategy":"try-catch","validationCode":"// ensure the server process is alive and initialized before requesting\nif !client.is_alive().await || !client.is_initialized().await {\n    anyhow::bail!(\"LSP server not ready; skipping request\");\n}","typeGuard":null,"tryCatchPattern":"match client.request(method, params, wait).await {\n    Ok(reply) => reply,\n    Err(e) if e.to_string() == \"LSP request channel closed\" => {\n        // server died mid-request: log, restart, optionally retry once\n        client.restart().await?;\n        client.request(method, params, wait).await\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Track child exit status so a dead server is detected before requests","Don't fire requests during client shutdown windows","Capture server stderr/exit codes to explain reader-task termination","Wrap request bursts in a liveness check"],"tags":["lsp","channel-closed","jsonrpc"],"backgroundTag":"broken-pipe","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"}