{"record":{"id":"8c05a9437ffc4748","repo":"Hmbown/CodeWhale","slug":"lsp-request-timed-out-for-method","errorCode":null,"errorMessage":"LSP request timed out for {method}","messagePattern":"LSP request timed out for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/lsp/client.rs","lineNumber":504,"sourceCode":"        })\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),\n            Err(_) => Err(anyhow!(\"LSP request timed out for {method}\")),\n        }\n    }\n\n    async fn shutdown(&self) {\n        let mut child = self.child.lock().await;\n        if let Some(mut c) = child.take() {\n            let _ = c.start_kill();\n            let _ = c.wait().await;\n        }\n        for task in &self.tasks {\n            task.abort();\n        }\n        self.pending.lock().await.clear();\n    }\n}\n\n/// Send a JSON value as one Content-Length-framed JSON-RPC message.\nasync fn send_message(tx: &mpsc::Sender<Vec<u8>>, value: &Value) -> Result<()> {","sourceCodeStart":486,"sourceCodeEnd":522,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/lsp/client.rs#L486-L522","documentation":"The whole request — send plus reply wait — was wrapped in a tokio timeout with the caller's `wait` budget. This error means the timeout elapsed before the server responded, and it names the method so the caller knows which request starved.","triggerScenarios":"Language server is slow or busy (indexing, heavy analysis) and replies after the wait budget; server hung or dead so no reply ever arrives; wait duration set too short for an expensive method (e.g. workspace symbol on a huge repo).","commonSituations":"rust-analyzer/gopls still indexing on first requests; tsserver on a very large project; hover/completion issued immediately after open before the server is ready; deadline tuning too aggressive in tests.","solutions":["Increase the wait duration for expensive methods or cold-start scenarios","Wait for server readiness (initialization + first diagnostics) before issuing requests","Retry the request once — slow-first-request is common while the server warms up","Check server logs/CPU to distinguish busy-but-alive from hung; restart if hung"],"exampleFix":"// before\nlet reply = client.request(\"textDocument/completion\", params, Duration::from_millis(500)).await;\n// after\nlet reply = client.request(\"textDocument/completion\", params, Duration::from_secs(10)).await;","handlingStrategy":"retry","validationCode":"// wait for server readiness before expensive first requests\nclient.wait_until_initialized(Duration::from_secs(30)).await?;","typeGuard":null,"tryCatchPattern":"match client.request(method, params, wait).await {\n    Ok(reply) => reply,\n    Err(e) if e.to_string().starts_with(\"LSP request timed out for\") => {\n        // one warm-up retry with a longer budget\n        client.request(method, params, wait * 2).await\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Delay requests until the server signals readiness (initialize reply, first publishDiagnostics)","Budget generously for cold-start when the server is still indexing","Classify timeouts: busy-but-alive servers deserve a retry; hung ones need restart","Track per-method latency to right-size per-method wait budgets"],"tags":["lsp","timeout","jsonrpc"],"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"}