Hmbown/CodeWhale · info

OAuth login was cancelled

Error message

OAuth login was cancelled

What it means

run_cancellable_oauth wraps an OAuth login future with a cancellation token; when cancellation fires before the future completes, it aborts the flow and returns this error. It is a normal, expected outcome of a user or caller cancelling an in-progress MCP OAuth login, not a malfunction.

Solutions

  1. Nothing is broken — simply run the OAuth login again and complete the browser authorization step
  2. If cancellations happen unexpectedly, check for UI shutdowns, tool-call timeouts, or duplicate login invocations cancelling each other
  3. Complete the browser authorization promptly after starting login to avoid cancelling flows
  4. Verify no automation is issuing competing login requests for the same server
Defensive patterns

Strategy: try-catch

Try / catch

match perform_oauth_login_for_server(&server).await {
    Err(e) if e.to_string() == "OAuth login was cancelled" => {
        eprintln!("login cancelled; rerun /mcp login to retry");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Cancelling an in-flight OAuth login: pressing the cancel key in the /mcp login UI, dropping the authenticate tool call, or triggering the CancellationToken passed to perform_oauth_login_for_server_with_cancel while the browser-based flow is pending.

Common situations: User closes the login dialog or navigates away before completing the browser authorization; a timeout-driven cancel; the client shuts down mid-login; user retries the login, cancelling the previous attempt.

Related errors


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

Appendix: source

Thrown at crates/tui/src/mcp/oauth.rs:1097

        perform_oauth_login_for_server_inner(
            name,
            server,
            explicit_scopes,
            callback_port,
            callback_url,
            network_policy,
        ),
    )
    .await
}

async fn run_cancellable_oauth<F, T>(cancellation_token: &CancellationToken, future: F) -> Result<T>
where
    F: std::future::Future<Output = Result<T>>,
{
    tokio::select! {
        biased;
        _ = cancellation_token.cancelled() => bail!("OAuth login was cancelled"),
        result = future => result,
    }
}

/// Shared gate + scope resolution for `/mcp login` and the model-driven
/// authenticate tool: URL-based servers only, no manual Authorization config,
/// scopes from explicit argument, config, or discovery (in that order).
async fn resolve_oauth_login(
    name: &str,
    server: &McpServerConfig,
    explicit_scopes: Option<Vec<String>>,
    network_policy: Option<&NetworkPolicyDecider>,
) -> Result<(String, ResolvedMcpOAuthScopes)> {
    let Some(url) = server.url.as_deref() else {
        bail!("OAuth login is only supported for URL-based MCP servers");
    };
    if server_has_manual_authorization(server) {
        bail!("MCP server '{name}' already has bearer/static Authorization configured");

View on GitHub (pinned to 73e0f67d83)