{"record":{"id":"f3f5f533c288203b","repo":"Hmbown/CodeWhale","slug":"mcp-connection-task-panicked","errorCode":null,"errorMessage":"MCP connection task panicked","messagePattern":"MCP connection task panicked","errorType":"panic","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/tui/src/mcp.rs","lineNumber":3801,"sourceCode":"            let network_policy = network_policy.clone();\n            joins.spawn(async move {\n                let connection = std::panic::AssertUnwindSafe(async {\n                    let _permit = permit.acquire_owned().await;\n                    McpConnection::connect_with_policy(\n                        name.clone(),\n                        config,\n                        &timeouts,\n                        network_policy.as_ref(),\n                    )\n                    .await\n                    .map(|mut connection| {\n                        connection.catalog_generation = catalog_generation;\n                        connection\n                    })\n                })\n                .catch_unwind()\n                .await\n                .unwrap_or_else(|_| Err(anyhow::anyhow!(\"MCP connection task panicked\")));\n                (name, connection)\n            });\n        }\n\n        joins\n    }\n\n    /// Connect to all enabled servers, returning errors for failed connections.\n    ///\n    /// Servers connect **concurrently** (bounded by [`Self::CONNECT_CONCURRENCY`]).\n    /// This used to be a sequential loop over `get_or_connect`, so every\n    /// server paid the slowest server's spawn+handshake from its own budget:\n    /// with the default 10s connect timeout, N servers meant a worst case of\n    /// N×10s before the pool was usable. Each connection still gets its own\n    /// configured connect timeout; one wedged server can no longer serialize\n    /// the rest.\n    ///\n    /// Semantics preserved from the sequential loop: only configured servers","sourceCodeStart":3783,"sourceCodeEnd":3819,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/mcp.rs#L3783-L3819","documentation":"MCP connection tasks are spawned with catch_unwind; if the underlying connect future panics, the panic is converted into a regular Err so the pool records it as a connection failure instead of tearing down the caller. The message intentionally hides panic details behind a stable label.","triggerScenarios":"A panic inside the per-server connect task (e.g. unwrap/ indexing bug in a connector or transport) while handshaking an MCP server.","commonSituations":"Bug in an MCP transport/SDK integration triggered by a malformed server response; a custom plugin connector panicking during handshake.","solutions":["Inspect logs/stderr for the original panic backtrace (panics usually print before being caught)","Identify the server whose connect panicked and reproduce its handshake in isolation","File/fix the panic in the connector or transport code — this message indicates an internal bug, not a config problem"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"let result = std::panic::catch_unwind(|| connector.connect())\n    .unwrap_or_else(|_| Err(anyhow!(\"MCP connection task panicked\")));\nif let Err(e) = result { log::error!(\"mcp connect panic: {e:#}\"); }","preventionTips":["Avoid unwrap/expect in transport and connector code","Fuzz or test connectors against malformed server responses","Keep panics logged with backtraces so the panic source is diagnosable"],"tags":["mcp","panic","internal-bug","async"],"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-22T06:17:15.046Z"}