Hmbown/CodeWhale · error

MCP server ' ': timed out after

Error message

MCP server '{}': {} timed out after {:?}

What it means

`request` waits on the child's stdout response channel with a hard deadline (`timeout`). If the deadline elapses before a matching response line arrives, the client bails with this timeout error instead of blocking forever on a wedged server. Each request has its own timeout, so this is per-call, not a global connection timeout.

Solutions

  1. Increase the request timeout for this server if it is legitimately slow (e.g. cold-start installs dependencies).
  2. Check the server logs (stderr) to see whether the request was received and what it is doing.
  3. Confirm the server emits responses on stdout as line-delimited JSON-RPC (stdout used for anything else, e.g. debug prints, breaks framing).
  4. Retry the request; if hangs are recurring, fix or replace the server handler that deadlocks.

Example fix

// before: tight timeout on a slow server
let client = spawn_with_timeouts(&config, Duration::from_secs(5), Duration::from_secs(5)).await?;
// after: larger request budget
let client = spawn_with_timeouts(&config, Duration::from_secs(10), Duration::from_secs(120)).await?;
Defensive patterns

Strategy: try-catch

Try / catch

match conn.request(method, params, timeout).await {
    Err(e) if e.to_string().contains("timed out after") => {
        eprintln!("{method} exceeded {timeout:?}; increase timeout or investigate the server handler");
        // optional: one retry with a longer timeout
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling `request` (from `spawn_with_timeouts` or later use) when the MCP child accepts the stdin write but never sends a JSON-RPC response line on stdout within the allotted `Duration`.

Common situations: The server hangs on the request (deadlocked handler, waiting on network/DB); the request timeout is set too low for a slow server (cold start, first-time tool install); the server responds on stderr but not stdout; a server-side infinite loop on a pathological input.

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@433685b202 (2026-09-15). Data as JSON: /api/errors/606662550a9be4f4. Report an issue: GitHub.

Appendix: source

Thrown at crates/mcp/src/stdio_client.rs:888

            // write loses the race and returns EPIPE. Which one wins is
            // platform- and timing-dependent (macOS reliably reports the write
            // error where Linux reports the EOF), so both report the death the
            // same way rather than leaking a bare "Broken pipe".
            if is_broken_pipe(&err) {
                bail!(
                    "MCP server '{server}': process closed stdin before answering {method}{}",
                    self.exit_note()
                );
            }
            return Err(err)
                .with_context(|| format!("MCP server '{server}': failed to send {method}"));
        }

        let deadline = Instant::now() + timeout;
        loop {
            let remaining = deadline.saturating_duration_since(Instant::now());
            if remaining.is_zero() {
                bail!("MCP server '{server}': {method} timed out after {timeout:?}");
            }
            let line = match self.responses.recv_timeout(remaining) {
                Ok(ChildStdoutMessage::Line(line)) => line,
                Ok(ChildStdoutMessage::Invalid(error)) => {
                    bail!(
                        "MCP server '{server}': invalid child stdout while awaiting {method}: {error}"
                    );
                }
                Err(RecvTimeoutError::Timeout) => {
                    bail!("MCP server '{server}': {method} timed out after {timeout:?}");
                }
                Err(RecvTimeoutError::Disconnected) => {
                    bail!(
                        "MCP server '{server}': process closed stdout before answering {method}{}",
                        self.exit_note()
                    );
                }
            };

View on GitHub (pinned to 433685b202)