{"record":{"id":"d361a6522e189abd","repo":"zeroclaw-labs/zeroclaw","slug":"mcp-server-server-name-timed-out-after-timeou","errorCode":null,"errorMessage":"MCP server `{server_name}` timed out after {timeout_secs}s during {operation}; outcome unknown and request was not replayed","messagePattern":"MCP server `(.+?)` timed out after (.+?)s during (.+?); outcome unknown and request was not replayed","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-tools/src/mcp_client.rs","lineNumber":661,"sourceCode":"            match send_result {\n                Err(_) => {\n                    let unknown_epoch = lifecycle.outcome_unknown_epoch();\n                    cancellation_guard.disarm();\n                    ::zeroclaw_log::record!(\n                        WARN,\n                        ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Timeout)\n                            .with_outcome(::zeroclaw_log::EventOutcome::Failure)\n                            .with_attrs(::serde_json::json!({\n                                \"mcp_server\": &server_name,\n                                \"rpc_method\": rpc_method,\n                                \"timeout_secs\": timeout_secs,\n                                \"outcome_unknown\": unknown_epoch.is_some(),\n                            })),\n                        \"mcp_client: MCP request timed out\"\n                    );\n                    if let Some(epoch) = unknown_epoch {\n                        self.spawn_recovery(epoch, operation.to_string());\n                        bail!(\n                            \"MCP server `{server_name}` timed out after {timeout_secs}s during \\\n                             {operation}; outcome unknown and request was not replayed\"\n                        );\n                    }\n                    bail!(\n                        \"MCP server `{server_name}` timed out after {timeout_secs}s before writing \\\n                         {operation}\"\n                    );\n                }\n                Ok(Ok(response)) => {\n                    cancellation_guard.disarm();\n                    return Ok(response);\n                }\n                Ok(Err(error)) => {\n                    if let Some(epoch) = lifecycle.outcome_unknown_epoch() {\n                        cancellation_guard.disarm();\n                        self.spawn_recovery(epoch, operation.to_string());\n                        return Err(error).with_context(|| {","sourceCodeStart":643,"sourceCodeEnd":679,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-tools/src/mcp_client.rs#L643-L679","documentation":"The JSON-RPC request was written to the server but no response arrived within the configured timeout. Because the server may still be processing it, the client deliberately does not replay the request; it arms an asynchronous recovery (transport reset + re-handshake) and bails, telling the caller the operation may or may not have taken effect.","triggerScenarios":"Slow tools (LLM-backed, large file scans) exceeding timeout_secs; a hung or deadlocked server; network drop after the request was sent; timeouts configured below the tool's documented worst case.","commonSituations":"Default timeouts used with heavyweight tools; servers that queue requests behind long jobs; transport stalls on loaded machines.","solutions":["Raise the per-tool timeout above the tool's realistic worst-case execution time","Check server-side logs to learn whether the operation actually completed before deciding to retry","Retry only idempotent operations directly; for writes, verify the effect on the server first — the client guarantees no automatic replay","If it recurs, profile why the server is slow rather than only raising the ceiling"],"exampleFix":"# before\ntool_timeout_secs = 30\n\n# after — sized to the slowest advertised tool\ntool_timeout_secs = 180","handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_outcome_unknown_timeout(err: &anyhow::Error) -> bool {\n    err.to_string().contains(\"outcome unknown and request was not replayed\")\n}","tryCatchPattern":"On this error the operation is ambiguous: retry reads directly once recovery completes; for writes, query the server for the effect (list the changed state) and only then re-issue — never blind-retry, the client intentionally does not replay.","preventionTips":["Set timeout_secs above each tool's realistic worst case (LLM-backed tools need minutes)","Design tool calls to be idempotent or queryable so outcome-unknown is recoverable","Watch the WARN 'MCP request timed out' events to tune timeouts before failures cascade"],"tags":["mcp","timeout","outcome-unknown","json-rpc"],"backgroundTag":"request-timeout","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}