{"record":{"id":"483f0793b59cbc9b","repo":"Hmbown/CodeWhale","slug":"lsp-semantic-request-timed-out-waiting-for-another-document","errorCode":null,"errorMessage":"LSP semantic request timed out waiting for another document","messagePattern":"LSP semantic request timed out waiting for another document","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/lsp/client.rs","lineNumber":438,"sourceCode":"                items,\n                document_version: Some(version),\n                diagnostic_version: published_version,\n            });\n        }\n    }\n\n    async fn request_for_document(\n        &self,\n        path: &Path,\n        text: &str,\n        method: &str,\n        params: Value,\n        wait: Duration,\n    ) -> Result<SemanticReply> {\n        let deadline = tokio::time::Instant::now() + wait;\n        let _gate = timeout(wait, self.diagnostics_gate.lock())\n            .await\n            .map_err(|_| anyhow!(\"LSP semantic request timed out waiting for another document\"))?;\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 semantic request timed out sending document\"))??;\n        let result = self\n            .request(\n                method,\n                params,\n                deadline.saturating_duration_since(tokio::time::Instant::now()),\n            )\n            .await?;\n        Ok(SemanticReply {\n            result,\n            document_version: Some(version),\n        })\n    }","sourceCodeStart":420,"sourceCodeEnd":456,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/lsp/client.rs#L420-L456","documentation":"request_for_document acquires the shared diagnostics_gate before touching the document, so semantic requests don't interleave with diagnostics publication. This error means it could not acquire that mutex within the wait budget — another task (typically diagnostics_for) held the gate for the entire window.","triggerScenarios":"A long-running diagnostics_for holds diagnostics_gate while waiting up to its full deadline for publications; multiple semantic requests queue behind the gate and later ones expire; caller passes a wait shorter than the gate holder's deadline.","commonSituations":"Hover/completion issued while a diagnostics publication is still pending; one large document monopolizing the gate during indexing; UI callers with short timeouts contending with background diagnostics.","solutions":["Increase the wait duration so it covers the gate holder's worst-case hold time","Shorten or chunk diagnostics_for's gate hold (publish outside the gate) to reduce contention","Queue semantic requests behind a single in-flight request instead of many concurrent waits","Retry the semantic request; contention is often transient"],"exampleFix":"// before\nlet reply = client.request_for_document(path, text, method, params, Duration::from_secs(1)).await;\n// after\nlet reply = client.request_for_document(path, text, method, params, Duration::from_secs(15)).await;","handlingStrategy":"try-catch","validationCode":"// don't enter with a wait smaller than a typical gate hold\nif wait < Duration::from_secs(1) { bail!(\"wait too small to acquire diagnostics_gate\"); }","typeGuard":null,"tryCatchPattern":"match client.request_for_document(path, text, method, params, wait).await {\n    Ok(reply) => reply,\n    Err(e) if e.to_string().contains(\"timed out waiting for another document\") => {\n        // gate held by diagnostics; back off and retry\n        tokio::time::sleep(Duration::from_millis(250)).await;\n        client.request_for_document(path, text, method, params, wait).await\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Pass a wait budget longer than diagnostics_for's maximum hold time","Limit concurrent semantic requests during diagnostics publication","Consider retrying with backoff — gate contention is usually transient","Keep diagnostics publication latency low so the gate frees quickly"],"tags":["lsp","timeout","lock-contention"],"backgroundTag":"request-timeout","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"}