Hmbown/CodeWhale · error · anyhow::Error

{backoff.last_error}

Error message

{backoff.last_error}

What it means

Rather than a fixed message, this error replays the recorded last_error from a connection's exponential backoff state. When a server is in its backoff window (a prior connect attempt failed and retry_after has not elapsed), any re-connect attempt immediately fails with the original diagnosis so the status row keeps showing why the server is down.

Solutions

  1. Wait until backoff.retry_after elapses, then the connect is attempted for real and this replay stops
  2. Fix the underlying cause recorded in backoff.last_error (check the original message for the real failure)
  3. Restart the session or remove the server from config if it should no longer be connected
Defensive patterns

Strategy: retry

Validate before calling

// check backoff state before attempting a connect
if let Some(b) = pool.connect_backoff.get(&name) {
    if std::time::Instant::now() < b.retry_after { return Err(anyhow!(b.last_error.clone())); }
}

Try / catch

match result {
    Err(e) if std::time::Instant::now() < backoff.retry_after => schedule_retry(backoff.retry_after - Instant::now()),
    other => other,
}

Prevention

When it happens

Trigger: Calling the pool's connect/refresh pass for a server whose name is in connect_backoff and whose backoff.retry_after is still in the future.

Common situations: A required MCP server crashed on startup (bad command, auth failure) and the UI re-checks status before the backoff timer expires; automated polling of server status during repeated failures.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


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

Appendix: source

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

                continue;
            }

            // Authority validated immediately above for this same source.
            if self
                .connections
                .get(&name)
                .is_some_and(McpConnection::is_transport_ready)
            {
                continue;
            }
            // Inside its cooldown a failed server costs nothing and still
            // tells the truth: the recorded diagnosis is replayed so the row
            // keeps reading `error`, rather than going quiet and looking
            // healthy because nobody asked.
            if let Some(backoff) = self.connect_backoff.get(&name)
                && std::time::Instant::now() < backoff.retry_after
            {
                errors.push((name, anyhow::anyhow!(backoff.last_error.clone())));
                continue;
            }
            if self.connecting.contains(&name) {
                // An earlier pass spawned this connect and it has not
                // resolved; a second pass must not spawn a duplicate.
                continue;
            }
            self.drop_connection(&name, "reconnect");
            self.connecting.insert(name.clone());
            pending.push((name, server_config));
        }
        (pending, errors)
    }

    /// Start connects for servers an explicit tool selection named. Unlike a
    /// boot pass the selection is the intent — cooldowns do not apply — but
    /// servers already ready or already in flight are left alone, and plugin
    /// authority is re-validated exactly as in

View on GitHub (pinned to 73e0f67d83)