Hmbown/CodeWhale · error

LSP semantic request timed out

Error message

LSP semantic request timed out

What it means

`request_for_document` wraps the semantic request in `tokio::time::timeout`; this error fires when the inner request does not complete within the allotted wait. The reply never arrived in time, so the semantic operation is abandoned.

Solutions

  1. Increase the wait duration passed to the request
  2. Check the LSP server is still alive and producing logs
  3. Retry the request once on timeout before failing the user action
  4. Verify the request id/response matching works (no dropped responses)

Example fix

// before
let wait = Duration::from_millis(500);
let reply = request_for_document(transport, path, method, params, wait).await?;
// after
let wait = Duration::from_secs(10); // semantic replies can be slow
let reply = request_for_document(transport, path, method, params, wait).await;
Defensive patterns

Strategy: retry

Validate before calling

// before issuing: ensure server responsive
let ping = tokio::time::timeout(Duration::from_secs(2), transport.request("shutdown", json!({}), Duration::from_secs(1))).await.is_ok();

Try / catch

match request_for_document(...).await {
    Err(e) if e.to_string().contains("timed out") => request_for_document(... with 3x wait).await,
    other => other,
}

Prevention

When it happens

Trigger: LSP server slow or hung answering the request; wait duration too short for large documents or slow servers; transport deadlock so no response is ever produced.

Common situations: Large monorepo files where rust-analyzer/clangd takes seconds to index; server crashed mid-request; wait configured to a few hundred milliseconds.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/3e2a0253418b68df. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/lsp/client.rs:130

    /// Synchronize and query one document atomically when the transport can
    /// prove that ordering. Diagnostic-only/legacy transports stay unverified.
    async fn request_for_document(
        &self,
        path: &Path,
        text: &str,
        method: &str,
        params: Value,
        wait: Duration,
    ) -> Result<SemanticReply> {
        timeout(wait, async {
            self.ensure_open(path, text).await?;
            Ok(SemanticReply {
                result: self.request(method, params, wait).await?,
                document_version: None,
            })
        })
        .await
        .map_err(|_| anyhow!("LSP semantic request timed out"))?
    }

    /// Ensure `path` is open with `text` (didOpen/didChange) so position-based
    /// requests can target it. Default is a no-op; real transports track opens.
    async fn ensure_open(&self, _path: &Path, _text: &str) -> Result<()> {
        Ok(())
    }

    /// A closed transport is never valid cache evidence. Diagnostic-only
    /// in-process implementations remain usable until their owner removes them.
    fn is_alive(&self) -> bool {
        true
    }

    /// Best-effort shutdown. Called via `LspManager::shutdown_all`.
    async fn shutdown(&self);
}

View on GitHub (pinned to 73e0f67d83)