{"record":{"id":"564daf5f5301e6f6","repo":"Hmbown/CodeWhale","slug":"lsp-diagnostics-timed-out-before-a-current-publication","errorCode":null,"errorMessage":"LSP diagnostics timed out before a current publication","messagePattern":"LSP diagnostics timed out before a current publication","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/lsp/client.rs","lineNumber":398,"sourceCode":"        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\"\n                    ));\n                }\n            };\n            if file != path_buf || published_version.is_some_and(|published| published != version) {","sourceCodeStart":380,"sourceCodeEnd":416,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/lsp/client.rs#L380-L416","documentation":"After successfully sending the document, diagnostics_for loops on the diagnostics broadcast channel waiting for a publishDiagnostics notification matching this file and version. This error is returned when the overall deadline expires before any current (matching) publication arrives.","triggerScenarios":"The server acknowledges the document change but never publishes diagnostics (or publishes only for an older version) before the deadline; the loop discards stale publications (wrong file/version) until time runs out.","commonSituations":"Servers that debounce or debounce-heavy diagnostics (rust-analyzer, tsserver) take longer than the caller's wait; server publishes diagnostics only after full analysis of a huge file; caller set a tight timeout.","solutions":["Increase the wait deadline to cover the server's diagnostic debounce latency","Verify the server actually sends publishDiagnostics for didChange (check capability / server logs)","Retry once with a fresh deadline; a transient slow publish resolves on retry","If the file/version never matches, check that text sent matches the on-disk path version tracking"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// confirm the server advertises diagnostics support before waiting\nlet caps = client.capabilities();\nif caps.text_document_sync.is_none() { bail!(\"server will not publish diagnostics\"); }","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 before a current publication\") => {\n        client.diagnostics_for(path, text, wait * 2).await.unwrap_or_default()\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Size the wait to the server's known diagnostic debounce latency","Avoid re-sending didChange while waiting, or the awaited version never matches","Confirm server capabilities include full/didChange diagnostics sync","Use server readiness signals before issuing diagnostics waits"],"tags":["lsp","timeout","diagnostics"],"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"}