{"record":{"id":"9b29a32bc83e358c","repo":"Hmbown/CodeWhale","slug":"lsp-diagnostics-timed-out-sending-document","errorCode":null,"errorMessage":"LSP diagnostics timed out sending document","messagePattern":"LSP diagnostics timed out sending document","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/lsp/client.rs","lineNumber":394,"sourceCode":"    async fn diagnostics_for(\n        &self,\n        path: &Path,\n        text: &str,\n        wait: Duration,\n    ) -> Result<DiagnosticPublication> {\n        // One receiver cannot serve concurrent polling safely: serialize the\n        // open/version/send/wait transaction, including semantic ensure_open.\n        let deadline = tokio::time::Instant::now() + wait;\n        let _gate = timeout(wait, self.diagnostics_gate.lock())\n            .await\n            .map_err(|_| anyhow!(\"LSP diagnostics timed out waiting for another document\"))?;\n        let path_buf = path.to_path_buf();\n        let (_, version) = timeout(\n            deadline.saturating_duration_since(tokio::time::Instant::now()),\n            self.open_or_change(path, text),\n        )\n        .await\n        .map_err(|_| anyhow!(\"LSP diagnostics timed out sending document\"))??;\n        loop {\n            let remaining = deadline.saturating_duration_since(tokio::time::Instant::now());\n            if remaining.is_zero() {\n                return Err(anyhow!(\n                    \"LSP diagnostics timed out before a current publication\"\n                ));\n            }\n            let mut rx = self.diagnostics_rx.lock().await;\n            let (file, published_version, items) = match timeout(remaining, rx.recv()).await {\n                Ok(Some(item)) => item,\n                Ok(None) => {\n                    return Err(anyhow!(\n                        \"LSP diagnostics channel closed before publishDiagnostics\"\n                    ));\n                }\n                Err(_) => {\n                    return Err(anyhow!(\n                        \"LSP diagnostics timed out before a current publication\"","sourceCodeStart":376,"sourceCodeEnd":412,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/lsp/client.rs#L376-L412","documentation":"diagnostics_for sends a didOpen/didChange for the document and waits, under an overall deadline, for the language server to reply with publishDiagnostics. This error means the initial open_or_change send itself could not complete within the caller's deadline (the tokio timeout fired on the send future), so the function aborts instead of publishing stale or no diagnostics.","triggerScenarios":"Calling diagnostics_for with a deadline already exhausted or too short; open_or_change blocked because the diagnostics_gate or outbound queue is saturated by earlier documents; LSP server unresponsive so the send future stalls past the deadline.","commonSituations":"Large monorepos where the server is still indexing and backpressure delays didChange; opening a file right as a deadline-based caller (e.g. a test or UI wait) expires; a hung language-server child process.","solutions":["Increase the deadline passed to diagnostics_for so the send has time to complete","Check that the language-server process is alive and responsive (logs, is_alive)","Serialize diagnostics_for calls so one document's backpressure does not starve another's send","If a server restart is suspected, reinitialize the client and retry"],"exampleFix":"// before\nlet diags = client.diagnostics_for(path, text, Duration::from_secs(2)).await;\n// after\nlet diags = client.diagnostics_for(path, text, Duration::from_secs(10)).await;","handlingStrategy":"try-catch","validationCode":"// ensure a non-trivial deadline remains before calling\nlet deadline = Instant::now() + wait;\nif deadline <= Instant::now() { bail!(\"deadline already expired\"); }","typeGuard":null,"tryCatchPattern":"match client.diagnostics_for(path, text, wait).await {\n    Ok(d) => d,\n    Err(e) if e.to_string().contains(\"timed out sending document\") => {\n        // extend budget / check server liveness, then retry once\n        retry_with_longer_deadline()\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Pass a deadline generous enough for the send plus a full publishDiagnostics wait","Keep diagnostics_for calls serialized to avoid outbound backpressure","Monitor language-server process liveness before waiting","Log server stderr so a wedged send is diagnosable"],"tags":["lsp","timeout","tokio"],"backgroundTag":"request-timeout","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T06:17:15.046Z"}