Hmbown/CodeWhale · info
OAuth login was cancelled
Error message
OAuth login was cancelled
What it means
Thrown by run_cancellable_oauth in crates/tui/src/mcp/oauth.rs when the CancellationToken fires before the OAuth login future completes. The tokio::select! is biased, so cancellation always wins over the login flow even if the browser callback is milliseconds away. This is a controlled, user-initiated abort of the MCP OAuth login flow, not a failure of the OAuth exchange itself, and no tokens are stored.
Source
Thrown at crates/tui/src/mcp/oauth.rs:462
&cancellation_token,
perform_oauth_login_for_server_inner(
name,
server,
explicit_scopes,
callback_port,
callback_url,
),
)
.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,
}
}
async fn perform_oauth_login_for_server_inner(
name: &str,
server: &McpServerConfig,
explicit_scopes: Option<Vec<String>>,
callback_port: Option<u16>,
callback_url: Option<&str>,
) -> Result<()> {
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 0c42157ee5)
Solutions
- Treat it as a benign abort: log at info/debug level and return the user to the MCP server list; do not surface it as a failure
- If the cancellation is unexpected, find what calls CancellationToken::cancel() on this token (shutdown path, dialog dismiss handler) and decouple it from the login flow
- Re-run the OAuth login command without triggering cancellation to complete the flow
Defensive patterns
Strategy: try-catch
Try / catch
match perform_oauth_login_for_server(&name, &server, None, None, None).await {
Err(err) if err.to_string().contains("OAuth login was cancelled") => {
tracing::info!(target: "mcp", "login aborted by user");
}
Err(err) => return report_login_failure(name, err),
Ok(()) => {}
} Prevention
- Distinguish cancellation from failure in the catch: cancelled logins should be info-level and non-blocking
- Keep UI cancel tokens scoped to the dialog that owns them so unrelated shutdowns cannot abort an active login
- Surface a non-modal 'login cancelled' notice instead of an error toast
When it happens
Trigger: perform_oauth_login_for_server (e.g. the TUI's MCP login command) is awaiting browser authorization or token exchange while the user presses the cancel/Escape key, the session shuts down, or anything else cancels the shared CancellationToken passed into run_cancellable_oauth.
Common situations: User closes or aborts the OAuth prompt before finishing authorization in the browser; app shutdown or TUI exit races an in-flight login; a UI timeout wired to the same cancellation token fires during a slow authorization-code callback.
Related errors
- MCP OAuth setup cancelled after plugin authority changed
- MCP SSE connect cancelled before authentication completed
- MCP SSE connect cancelled before the request completed
- SSE transport cancelled before endpoint was discovered
- invalid Codewhale-owned xAI OAuth generation; expected xai-a
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/a00a5d7897717db6.
Report an issue: GitHub.