{"record":{"id":"b1375c3cbf308191","repo":"zeroclaw-labs/zeroclaw","slug":"mcp-server-server-name-exhausted-the-timeout","errorCode":null,"errorMessage":"MCP server `{server_name}` exhausted the {timeout_secs}s budget recovering before writing {operation}","messagePattern":"MCP server `(.+?)` exhausted the (.+?)s budget recovering before writing (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-tools/src/mcp_client.rs","lineNumber":704,"sourceCode":"\n                    cancellation_guard.disarm();\n                    let recoverable = error.downcast_ref::<McpTransportError>().is_some();\n                    if recoverable && pre_write_retries < MAX_RECONNECT_ATTEMPTS {\n                        pre_write_retries += 1;\n                        let observed_epoch = lifecycle.pre_write_epoch().unwrap_or(0);\n                        let recovery = self.start_recovery(observed_epoch, operation.to_string());\n                        match timeout_at(deadline, recovery).await {\n                            Ok(Ok(result)) => result?,\n                            Ok(Err(join_error)) => {\n                                return Err(anyhow::Error::new(join_error)).with_context(|| {\n                                    format!(\n                                        \"MCP server `{server_name}` recovery task failed before \\\n                                         writing {operation}\"\n                                    )\n                                });\n                            }\n                            Err(_) => {\n                                bail!(\n                                    \"MCP server `{server_name}` exhausted the {timeout_secs}s \\\n                                     budget recovering before writing {operation}\"\n                                );\n                            }\n                        }\n                        continue;\n                    }\n                    return Err(error).with_context(|| {\n                        format!(\"MCP server `{server_name}` error during {operation}\")\n                    });\n                }\n            }\n        }\n    }\n\n    /// Call a tool on this server. Returns the raw JSON result.\n    pub async fn call_tool(\n        &self,","sourceCodeStart":686,"sourceCodeEnd":722,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-tools/src/mcp_client.rs#L686-L722","documentation":"Before this request could be written, a transport error triggered an automatic reconnect; dispatch_rpc waits for that recovery within the same overall deadline, and this error means recovery consumed the entire remaining budget without finishing. The request was never sent — retry is safe — but the connection was still unhealthy at the deadline.","triggerScenarios":"A slow-starting server process (stdio spawn, dependency loading) whose reset + re-handshake exceeds the remaining budget; recovery racing a nearly-expired deadline; very small timeout values paired with cold-starting servers.","commonSituations":"Heavy Node/Python MCP servers cold-starting slower than the configured timeout; crash-looping servers where every recovery attempt restarts them and burns the full budget.","solutions":["Retry once the server has finished starting; the request was not written so there is no duplicate risk","Increase timeout_secs to cover the server's cold-start plus re-handshake time","Make the server start faster (lazy imports, fewer deps) instead of only raising timeouts","If it persists, check for crash-looping: each failed start wastes a full budget window"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_recovery_budget_exhausted(err: &anyhow::Error) -> bool {\n    err.to_string().contains(\"exhausted the\") && err.to_string().contains(\"budget recovering\")\n}","tryCatchPattern":"Retry once after giving the server time to finish starting — the request was never written. Persistent failures mean the server cold-start or crash-loop exceeds the budget; fix that before more retries.","preventionTips":["Raise timeout_secs to cover server cold-start plus re-handshake for heavy Node/Python servers","Keep MCP server startup lean (lazy imports) when timeouts are tight","Detect crash-looping servers and alert rather than burning budget windows on them"],"tags":["mcp","timeout","recovery","reconnect"],"backgroundTag":"recovery-timeout","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}