{"record":{"id":"83c218a3242bf721","repo":"Hmbown/CodeWhale","slug":"mcp-connection-disappeared-for-server-name","errorCode":null,"errorMessage":"MCP connection disappeared for {server_name}","messagePattern":"MCP connection disappeared for (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/mcp.rs","lineNumber":3172,"sourceCode":"        if let Some(source) = plugin_source\n            && let Err(error) = source.validate_before_use(server_name, \"use\")\n        {\n            self.drop_connection(server_name, \"plugin authority revoked or changed\");\n            return Err(error);\n        }\n\n        // Authority was just validated above for this same source; checking\n        // it again here would re-hash the bundle within one dispatch (#6209).\n        let is_ready = self\n            .connections\n            .get(server_name)\n            .map(McpConnection::is_transport_ready)\n            .unwrap_or(false);\n        if is_ready {\n            return self\n                .connections\n                .get_mut(server_name)\n                .ok_or_else(|| anyhow::anyhow!(\"MCP connection disappeared for {server_name}\"));\n        }\n\n        // Take (don't drop) the stale connection: if the reconnect attempt\n        // below fails, the previous connection is restored so its last-good\n        // tool catalog stays model-visible during the outage instead of\n        // disappearing with a dropped transport (#6187).\n        let previous_connection = self.connections.remove(server_name);\n        if previous_connection.is_some() {\n            tracing::debug!(\n                target: \"mcp\",\n                server = %server_name,\n                reason = \"reconnect\",\n                \"detached MCP connection for reconnect\"\n            );\n        }\n\n        // Check static config first, then dynamic servers\n        let server_config = self","sourceCodeStart":3154,"sourceCodeEnd":3190,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/mcp.rs#L3154-L3190","documentation":"After checking that a connection reports is_transport_ready, the pool looks it up in self.connections and expects it to still be present. Hitting this error means the ready-check and the map lookup raced: the connection vanished between the two steps. It is an internal invariant violation, not an expected user-facing condition.","triggerScenarios":"Concurrent mutation of the pool's connections map (shutdown, reconnect taking the stale connection via .take(), or removal by another task) between the is_ready probe and get_mut(server_name).","commonSituations":"Reconnect logic racing a concurrent tool dispatch; pool teardown while a request is resolving a connection; dynamic server removal concurrent with a call.","solutions":["Retry the operation; the pool will reconnect lazily on the next dispatch.","If reproducible, look for unsynchronized mutation of pool connections while a dispatch is in flight.","Hold the pool lock across the ready-check and lookup, or re-fetch the connection after the probe.","Report it as a bug with a trace if it occurs without concurrent use."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Probe readiness and presence atomically where the API allows\nlet conn = pool.try_get_ready_connection(server_name); // single lookup instead of check-then-get","typeGuard":null,"tryCatchPattern":"match pool.call_tool(server, tool, input) {\n    Err(e) if e.to_string().contains(\"MCP connection disappeared\") => {\n        // transient race: retry once; pool reconnects lazily\n        pool.call_tool(server, tool, input).await?\n    }\n    other => other?,\n}","preventionTips":["Don't mutate pool connections concurrently with dispatches.","Prefer a single get-or-connect call over separate ready-check + lookup.","Serialize per-server reconnects under one lock.","Retry once on this error before treating the server as down."],"tags":["mcp","race-condition","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}