xai-org/grok-build · error · OidcError
OidcError::CallbackTimeout
Error message
OidcError::CallbackTimeout
What it means
The OIDC loopback login flow waits for the browser/IDP to redirect to the local callback server with an authorization code. This error is thrown by `race_callback_and_client_ui` when the `tokio::time::timeout(AUTH_CALLBACK_TIMEOUT, ...)` wrapper expires (~10 minutes, per AUTH_CALLBACK_TIMEOUT) without any code arriving on the callback channel. It means the user never completed the browser authorization in the allotted window.
Source
Thrown at crates/codegen/xai-grok-shell/src/auth/oidc/login.rs:285
while let Some(code) = code_rx.recv().await {
match parse_pasted_input(&code) {
Ok(result) => {
tracing::debug!("OIDC: received code via client paste");
let _ = client_tx.send(Ok(result)).await;
return;
}
Err(e) => {
tracing::debug!(error = %e, "OIDC: invalid client paste input");
}
}
}
};
drop(tx);
let result = tokio::select! {
r = tokio::time::timeout(AUTH_CALLBACK_TIMEOUT, rx.recv()) => {
r.map_err(|_| anyhow::Error::new(OidcError::CallbackTimeout))?
.ok_or_else(|| anyhow::Error::new(OidcError::CallbackChannelClosed))?
}
_ = client_bridge => {
rx.recv().await
.ok_or_else(|| anyhow::Error::new(OidcError::CallbackChannelClosed))?
}
};
let _ = shutdown_tx.send(());
let _ = server.await;
result.map_err(|e| anyhow::Error::new(OidcError::CallbackAuthFailed(e)))
}
/// Race loopback callback against stdin paste.
async fn race_callback_and_stdin(
listener: TcpListener,
enable_stdin: bool,View on GitHub (pinned to bc7f02eddd)
Solutions
- Re-run the login command and complete the browser authorization promptly (within ~10 minutes).
- Verify the redirect_uri (http://127.0.0.1:<port>/callback) was not blocked and the browser actually opened; if not, copy the printed URL manually.
- Check IDP availability/SSO latency; if 10 minutes is too short for your SSO flow, increase AUTH_CALLBACK_TIMEOUT and rebuild.
- Ensure the loopback port (56121 or ephemeral) is not firewalled so the callback can reach the local server.
Example fix
// before (timeout elapses with default) const AUTH_CALLBACK_TIMEOUT: Duration = Duration::from_secs(600); // after: allow more time for slow SSO flows const AUTH_CALLBACK_TIMEOUT: Duration = Duration::from_secs(1800);
Defensive patterns
Strategy: try-catch
Validate before calling
let cfg = config.oidc.as_ref().ok_or("oidc not configured")?;
// preflight: check the authorize URL is reachable before starting the flow
reqwest::get(&format!("{}/.well-known/openid-configuration", cfg.issuer)).await?; Type guard
fn is_callback_timeout(err: &anyhow::Error) -> bool {
err.downcast_ref::<OidcError>()
.map_or(false, |e| matches!(e, OidcError::CallbackTimeout))
} Try / catch
match run_login_flow(config, auth_manager, channels).await {
Ok((auth, created)) => /* ... */,
Err(e) if is_callback_timeout(&e) => {
eprintln!("Login timed out; re-run and complete browser auth within 10 minutes");
}
Err(e) => return Err(e),
} Prevention
- Run login interactively and start the browser flow when you can finish it immediately
- Warn users up front that the login window is ~10 minutes
- Avoid suspending the machine mid-login
- Keep AUTH_CALLBACK_TIMEOUT generous relative to your SSO latency
When it happens
Trigger: tokio::time::timeout(AUTH_CALLBACK_TIMEOUT, rx.recv()) returns Err(Elapsed) while racing the loopback HTTP callback server against the client UI bridge in race_callback_and_client_ui, i.e. rx.recv() did not yield an authorization code within AUTH_CALLBACK_TIMEOUT.
Common situations: User opened the authorize URL but never finished login at the IDP; browser tab was closed; corporate SSO page hung; machine was suspended mid-login; user walked away from an interactive `login` command.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- OidcError::CallbackChannelClosed
- wait failed: {body}
- WebSocket connection timed out after {} seconds
- GCS download stalled: no data received for {chunk_timeout:?}
- command timed out after {}s
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/1da430e7656eb79b.
Report an issue: GitHub.