Hmbown/CodeWhale · error · anyhow::Error
Failed to store MCP connection for
Error message
Failed to store MCP connection for {server_name} What it means
store_ready_connection() succeeded in inserting the newly connected McpConnection, but the immediately following self.connections.get_mut(server_name) — used to return a mutable handle — found nothing. This is an internal race/invariant break: the just-stored connection was removed between the two steps.
Solutions
- Retry the call; the pool will reconnect on demand.
- Serialize reconnect/store operations for a given server under one lock.
- Return the connection directly from store_ready_connection instead of re-fetching from the map.
- If it reproduces without concurrency, file a bug with logs.
Defensive patterns
Strategy: retry
Try / catch
match pool.call_tool(server, tool, input) {
Err(e) if e.to_string().contains("Failed to store MCP connection") => {
// race with pool mutation: retry; the pool will reconnect
pool.call_tool(server, tool, input).await?
}
other => other?,
} Prevention
- Avoid teardown/reconnection of the pool while calls are in flight.
- Hold a single lock across store and lookup for a given server.
- Return the stored handle from the store function rather than re-fetching.
- Retry once on this error; it is a transient race, not a config problem.
When it happens
Trigger: Concurrent code removing or taking entries from pool.connections (teardown, reconnect of another path, dynamic server removal) in the window between store_ready_connection and get_mut.
Common situations: Pool shutdown racing a lazy connect; two tasks reconnecting the same server simultaneously; dynamic-server eviction concurrent with first use.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- MCP connection disappeared for
- active plugin registry is missing its pre-dotenv…
- Failed to call MCP method
- MCP configuration changed while connecting
- A managed, project or plugin connector already uses this…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/d8b2d3c9b31a88b4.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/mcp.rs:3229
Err(error) => {
self.note_connect_failure(server_name, &error);
if let Some(previous) = previous_connection {
tracing::debug!(
target: "mcp",
server = %server_name,
"reconnect failed; restored the previous MCP connection and its last-good catalog"
);
self.connections.insert(server_name.to_string(), previous);
}
return Err(error);
}
};
connection.catalog_generation = self.catalog_generation.load(Ordering::SeqCst);
self.store_ready_connection(server_name.to_string(), connection)?;
self.connections
.get_mut(server_name)
.ok_or_else(|| anyhow::anyhow!("Failed to store MCP connection for {server_name}"))
}
/// Retry exactly one server against the configuration already owned by
/// this pool.
///
/// Unlike normal lazy tool dispatch, an explicit row retry must not notice
/// a concurrent config mtime and invalidate healthy siblings. Config edits
/// remain owned by the explicit reload path; this operation only replaces
/// the named transport.
pub async fn retry_connection(&mut self, server_name: &str) -> Result<&mut McpConnection> {
self.require_server(server_name)?;
// A person asked for this one by name. Clear the cooldown so the
// attempt happens now and, if it fails again, the ladder restarts
// from the short end rather than from wherever it had climbed to.
// Explicit intent restarts supervision: the cooldown, the dead mark,
// and any park all clear, so the supervisor resumes watching whatever
// this retry stores — or stays quiet while the server is connectionless.
self.connect_backoff.remove(server_name);View on GitHub (pinned to 73e0f67d83)