Hmbown/CodeWhale · warning · anyhow::Error

MCP configuration changed while connecting

Error message

MCP configuration changed while connecting {name}; retry against the current config

What it means

store_ready_connection refuses to register a freshly completed MCP connection when the tool catalog generation has advanced since the connect started. This means the MCP config was edited mid-handshake and the connection's catalog snapshot is stale, so using it would serve tools that no longer match the configured servers.

Solutions

  1. Retry the connection: the error is intentionally self-healing — re-run the connect against the current config so a new connection is built with the latest catalog generation
  2. Re-check the server still exists in the current config before retrying (require_server may also fail)
  3. If it recurs, avoid editing the MCP config while the TUI is starting up, or wait for connections to settle before reloading

Example fix

// retry against current config
match pool.store_ready_connection(name.clone(), conn) {
    Err(e) if e.to_string().contains("retry against the current config") => {
        pool.connect_server(&name).await?; // rebuild with current catalog
    }
    other => other?,
}
Defensive patterns

Strategy: retry

Validate before calling

// before storing, confirm the generation still matches
if connection.catalog_generation != pool.current_catalog_generation() {
    pool.connect_server(&name).await?; // rebuild against current config
}

Try / catch

match store_ready_connection(name, conn) {
    Err(e) if e.to_string().contains("retry against the current config") => retry_connect(name),
    other => other,
}

Prevention

When it happens

Trigger: Calling store_ready_connection (via the MCP connect flow) after a concurrent config reload bumped current_catalog_generation(); e.g. the user edited ~/.codewhale/mcp.json or toggled a reviewed plugin while a server was still connecting.

Common situations: User edits MCP config or enables/disables a plugin in another window while the TUI is still handshaking servers at startup; hot-reload of mcp.json racing slow server startup.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/c9cd022295cbdcd9. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/mcp.rs:3308

            Err(error) => {
                self.note_connect_failure(server_name, &error);
                return Err(error);
            }
        };
        connection.catalog_generation = self.current_catalog_generation();
        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}"))
    }

    pub(crate) fn store_ready_connection(
        &mut self,
        name: String,
        connection: McpConnection,
    ) -> Result<()> {
        self.require_server(&name)?;
        anyhow::ensure!(
            connection.catalog_generation == self.current_catalog_generation(),
            "MCP configuration changed while connecting {name}; retry against the current config"
        );
        if let Some(source) = connection.config().reviewed_plugin.as_ref() {
            source.validate_before_use(&name, "use")?;
        }
        // A successful connect settles the auth question for this server,
        // and the cooldown with it — plus any supervisor dead mark or park,
        // since a stored-ready connection is alive by construction.
        self.connecting.remove(&name);
        self.connect_backoff.remove(&name);
        self.supervised_dead.remove(&name);
        self.supervised_parked.remove(&name);
        if self.needs_auth_servers.remove(&name) {
            self.needs_auth_generation = self.needs_auth_generation.wrapping_add(1);
        }
        self.connections.insert(name, connection);
        Ok(())

View on GitHub (pinned to 73e0f67d83)