{"record":{"id":"a9b2857066ed095d","repo":"Kuberwastaken/claurst","slug":"lsp-request-channel-closed-server","errorCode":null,"errorMessage":"LSP request '{}' channel closed (server: {})","messagePattern":"LSP request '(.+?)' channel closed \\(server: (.+?)\\)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-rust/crates/core/src/lsp.rs","lineNumber":325,"sourceCode":"                .writer\r\n                .as_ref()\r\n                .ok_or_else(|| anyhow::anyhow!(\"LSP client already shut down\"))?;\r\n            let mut w = writer.lock().await;\r\n            send_message(&mut w, &body).await?;\r\n        }\r\n\r\n        let response =\r\n            tokio::time::timeout(std::time::Duration::from_secs(30), rx)\r\n                .await\r\n                .map_err(|_| {\r\n                    anyhow::anyhow!(\r\n                        \"LSP request '{}' timed out (server: {})\",\r\n                        method,\r\n                        self.server_name\r\n                    )\r\n                })?\r\n                .map_err(|_| {\r\n                    anyhow::anyhow!(\r\n                        \"LSP request '{}' channel closed (server: {})\",\r\n                        method,\r\n                        self.server_name\r\n                    )\r\n                })?;\r\n\r\n        if let Some(err) = response.get(\"error\") {\r\n            return Err(anyhow::anyhow!(\r\n                \"LSP error from {}: {}\",\r\n                self.server_name,\r\n                err\r\n            ));\r\n        }\r\n        Ok(response[\"result\"].clone())\r\n    }\r\n\r\n    /// Send a JSON-RPC notification (fire-and-forget, no response expected).\r\n    async fn send_notification_inner(\r","sourceCodeStart":307,"sourceCodeEnd":343,"githubUrl":"https://github.com/Kuberwastaken/claurst/blob/b0637c97ec34144387cbf2f74f65df6d16a6cef1/src-rust/crates/core/src/lsp.rs#L307-L343","documentation":"Thrown in `LspClient::send_request_inner` when the oneshot channel carrying the JSON-RPC response is dropped before a reply arrives. The reader task (`dispatch_incoming`) resolves pending requests; if it exits (server stdout closed, server crashed) it drops all pending senders, so `rx` yields `RecvError`. This means the language server died or closed its stdout while a request was in flight, distinct from a 30s timeout.","triggerScenarios":"Any request via send_request_inner (initialize, hover, definition, references, document_symbols, shutdown) where the server process exits or its stdout pipe closes after the request was written but before the response is read.","commonSituations":"LSP server binary segfaults or panics mid-request; server exits due to OOM kill; user's tooling killed the child process; server binary version mismatch causing an early exit; stdin closure triggers server shutdown while a request is pending.","solutions":["Check that the configured LSP server binary runs and stays alive (run it manually in stdio mode and issue a request).","Restart the LSP manager / client so a fresh server process is spawned, then retry the request.","Check server logs and system logs (dmesg/journalctl) for crash, OOM, or signal termination of the server process.","Verify the server version is compatible with the request params sent (e.g. capabilities declared in initialize)."],"exampleFix":"// before: fire-and-forget call with no handling of dead server\nlet hover = manager.hover(path, root, line, col).await?;\n// after: detect dead server, restart, retry once\nlet hover = match manager.hover(path, root, line, col).await {\n    Ok(h) => h,\n    Err(e) if e.to_string().contains(\"channel closed\") => {\n        manager.shutdown_all().await;\n        manager.hover(path, root, line, col).await?\n    }\n    Err(e) => return Err(e),\n};","handlingStrategy":"retry","validationCode":"// Verify the server binary exists before starting requests\nif !which(config.command).is_ok() { return Err(\"server binary not found\"); }","typeGuard":"fn client_alive(client: &LspClient) -> bool { client.writer.is_some() }","tryCatchPattern":"match manager.hover(path, root, line, col).await {\n    Ok(h) => h,\n    Err(e) if e.to_string().contains(\"channel closed\") => {\n        manager.shutdown_all().await; // respawn and retry once\n        manager.hover(path, root, line, col).await.unwrap_or(None)\n    }\n    Err(_) => None,\n}","preventionTips":["Pin and smoke-test the language server binary version in your environment setup.","Wrap feature calls with a restart-and-retry helper that detects dead-server errors.","Monitor server stderr/stdout logging for early exit causes (OOM, panics)."],"tags":["lsp","ipc","process-crash","rust"],"backgroundTag":"broken-pipe","analyzedSha":"b0637c97ec34144387cbf2f74f65df6d16a6cef1","analyzedAt":"2026-09-10T00:24:58.650Z","contentChangedAt":"2026-09-10T00:24:58.650Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}