{"record":{"id":"8aaffb66792db47d","repo":"ultraworkers/claw-code","slug":"mcp-registry-lock-poisoned","errorCode":null,"errorMessage":"mcp registry lock poisoned","messagePattern":"mcp registry lock poisoned","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"rust/crates/runtime/src/mcp_tool_bridge.rs","lineNumber":100,"sourceCode":"        Self::default()\n    }\n\n    pub fn set_manager(\n        &self,\n        manager: Arc<Mutex<McpServerManager>>,\n    ) -> Result<(), Arc<Mutex<McpServerManager>>> {\n        self.manager.set(manager)\n    }\n\n    pub fn register_server(\n        &self,\n        server_name: &str,\n        status: McpConnectionStatus,\n        tools: Vec<McpToolInfo>,\n        resources: Vec<McpResourceInfo>,\n        server_info: Option<String>,\n    ) {\n        let mut inner = self.inner.lock().expect(\"mcp registry lock poisoned\");\n        inner.insert(\n            server_name.to_owned(),\n            McpServerState {\n                server_name: server_name.to_owned(),\n                status,\n                tools,\n                resources,\n                server_info,\n                error_message: None,\n            },\n        );\n    }\n\n    pub fn get_server(&self, server_name: &str) -> Option<McpServerState> {\n        let inner = self.inner.lock().expect(\"mcp registry lock poisoned\");\n        inner.get(server_name).cloned()\n    }\n","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/ultraworkers/claw-code/blob/08106b0c3771ef5b4a5aa176acccd460e88b7325/rust/crates/runtime/src/mcp_tool_bridge.rs#L82-L118","documentation":"Panic from McpToolBridge/McpRegistry::register_server (mcp_tool_bridge.rs:100): inserting a server's state (status, tools, resources, server_info) takes the registry Mutex, and .expect(\"mcp registry lock poisoned\") unwinds when that Mutex was poisoned by an earlier panic on a thread holding it. Registration happens during MCP server connection setup, so one poisoned lock breaks every subsequent server connection.","triggerScenarios":"Calling register_server after the MCP connect/lifecycle path panicked earlier while holding this registry's lock — e.g. a JSON-RPC handshake unwrap, serde parse panic, or the \"MCP tool call thread panicked\" path seen at mcp_tool_bridge.rs:238-246 which catches a tool-call panic but can occur while lock discipline was already broken elsewhere.","commonSituations":"An MCP server returns malformed JSON on initialize and a parse unwrap panics with the lock held; later reconnect attempts call register_server and panic in a loop; multi-server setups where one bad server poisons registration for all others.","solutions":["RUST_BACKTRACE=1 and fix the first panic under the lock — commonly an unwrap on malformed MCP server responses; convert to error propagation","Restart the process; the poisoned Mutex never heals","Maintainer fix: self.inner.lock().unwrap_or_else(|poison| poison.into_inner()) — a HashMap insert is safe even after a foreign panic","Keep MCP server I/O and deserialization outside the registry critical section so protocol bugs can't poison the lock"],"exampleFix":"// before (runtime/src/mcp_tool_bridge.rs:100)\nlet mut inner = self.inner.lock().expect(\"mcp registry lock poisoned\");\n\n// after\nlet mut inner = self\n    .inner\n    .lock()\n    .unwrap_or_else(|poison| poison.into_inner());","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let registered = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    bridge.register_server(name, status, tools, resources, info);\n}));\nif registered.is_err() {\n    // poisoned registry: rebuild bridge before reconnecting servers\n    bridge = McpToolBridge::new();\n}","preventionTips":["Parse and validate MCP initialize responses before taking the registry lock; protocol bugs must not poison registration","One poisoned lock breaks all subsequent server connections — monitor for the first panic, not the cascade","Keep connection retry loops from hammering register_server after a panic; rebuild the registry instead"],"tags":["panic","mutex","lock-poisoning","mcp","rust"],"backgroundTag":"mutex-lock-poisoned","analyzedSha":"08106b0c3771ef5b4a5aa176acccd460e88b7325","analyzedAt":"2026-08-18T00:29:38.590Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}