{"record":{"id":"751b58bbab6fc33a","repo":"zeroclaw-labs/zeroclaw","slug":"mcp-server-server-name-is-unavailable-a-prior","errorCode":null,"errorMessage":"MCP server `{server_name}` is unavailable: a prior request's outcome became unknown and recovery failed; not writing on an unrecovered session","messagePattern":"MCP server `(.+?)` is unavailable: a prior request's outcome became unknown and recovery failed; not writing on an unrecovered session","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/zeroclaw-tools/src/mcp_client.rs","lineNumber":493,"sourceCode":"                result\n                    .as_ref()\n                    .err()\n                    .and_then(|error| error.downcast_ref::<McpTransportError>()),\n                Some(McpTransportError::RecoveryPending)\n            ) {\n                continue;\n            }\n            return result;\n        }\n    }\n\n    /// Block until no recovery is pending, or fail closed if recovery has\n    /// permanently failed. Returns immediately when the connection is healthy.\n    async fn wait_recovery_ready(&self) -> Result<()> {\n        loop {\n            if self.recovery.is_poisoned() {\n                let server_name = self.inner.lock().await.config.name.clone();\n                bail!(\n                    \"MCP server `{server_name}` is unavailable: a prior request's outcome became \\\n                     unknown and recovery failed; not writing on an unrecovered session\"\n                );\n            }\n            if !self.recovery.recovery_pending() {\n                return Ok(());\n            }\n            // Register for a wakeup *before* re-checking so we cannot miss a\n            // concurrent `finish`/`poison` pulse.\n            let notified = self.recovery.notify.notified();\n            if self.recovery.is_poisoned() {\n                continue;\n            }\n            if !self.recovery.recovery_pending() {\n                return Ok(());\n            }\n            notified.await;\n        }","sourceCodeStart":475,"sourceCodeEnd":511,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-tools/src/mcp_client.rs#L475-L511","documentation":"When a request's outcome became unknown (timeout after the write), the client resets the transport and re-handshakes; if that recovery fails (transport reset error or rejected re-handshake in reestablish), the session is poisoned and every later call fails closed with this error instead of writing on an unrecovered session. It is deliberately terminal for this connection handle.","triggerScenarios":"The server process died or its stdio pipe closed while recovery ran; an HTTP MCP endpoint went down; the re-handshake itself got rejected (server now in a bad state); repeated timeouts where recovery never completes within reach.","commonSituations":"MCP server crashing under load or OOM-killed mid-request; the server restarted out-of-band during a long tool call; flaky network links to HTTP transports.","solutions":["Check the preceding ERROR log 'mcp_client: asynchronous recovery failed' — its error names why reset or re-handshake failed","Verify the server process is running (or the HTTP endpoint reachable) and fix that root cause first","Reconnect by creating a fresh connection/client for that server; the poisoned barrier is only cleared by a new successful connect","If crashes recur, raise the tool timeout or lower request frequency so recovery is needed less often"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":"fn is_poisoned_session(err: &anyhow::Error) -> bool {\n    err.to_string().contains(\"not writing on an unrecovered session\")\n}","tryCatchPattern":"Treat as terminal for this client handle: stop calling, log the paired recovery failure, fix/restart the server, then create a fresh connection. Retrying on the poisoned handle always fails.","preventionTips":["Monitor the 'asynchronous recovery failed' ERROR events — they precede the poisoned state","Keep MCP servers alive under load (memory limits, supervision) so recovery succeeds","Recreate clients on long-lived services instead of assuming a connection is immortal"],"tags":["mcp","recovery","fail-closed","connection"],"backgroundTag":"unrecoverable-session","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}