xai-org/grok-build · error
external auth provider `{command}` timed out after 300s
Error message
external auth provider `{command}` timed out after 300s What it means
After spawning the external auth provider, the flow waits up to 300 seconds for it to finish via tokio::time::timeout around wait_with_output(). If the child does not exit in 300s, the future is dropped (killing the wait) and this error is returned. It exists so a hung provider cannot hang the login flow forever.
Source
Thrown at crates/codegen/xai-grok-shell/src/auth/flow.rs:240
tracing::debug!(line = trimmed, "auth: provider stderr");
cb(trimmed);
}
Err(e) => {
tracing::warn!(error = %e, "auth: error reading provider stderr");
break;
}
}
}
}))
} else {
None
};
let output = tokio::time::timeout(
std::time::Duration::from_secs(300),
child.wait_with_output(),
)
.await
.map_err(|_| anyhow::anyhow!("external auth provider `{command}` timed out after 300s"))?
.map_err(|e| anyhow::anyhow!("external auth provider `{command}` IO error: {e}"))?;
if let Some(task) = stderr_task {
let _ = task.await;
}
let mut auth = parse_output(&output)
.map_err(|e| anyhow::anyhow!("external auth provider `{command}`: {e}"))?;
let principal_policy =
crate::auth::oidc::login_principal_policy(auth_manager.grok_com_config());
crate::auth::oidc::enforce_login_principal(
principal_policy.as_ref(),
crate::auth::oidc::peek_access_token_principal_id(&auth.key).as_deref(),
)?;
match (over_stale_credential, auth_manager.current_or_expired()) {
(true, Some(prev)) => auth.carry_user_profile_from(&prev),
_ => auth_manager.enrich_auth_inline(&mut auth).await,
}
let auth = auth_manager
.update(auth)View on GitHub (pinned to bc7f02eddd)
Solutions
- Run the provider command manually with the same inputs to see where it blocks; fix the provider's blocking step.
- For headless environments, configure the provider for non-interactive mode (device-code flow or pre-fetched token).
- Check the callback port is not occupied and that browsers/loopback access works if the provider waits for an OAuth redirect.
- Wrap/widen any provider-side timeout so it exits on its own with a clear error before 300s.
Defensive patterns
Strategy: retry
Validate before calling
// before login, confirm the provider can run non-interactively provider_cmd --check || echo 'provider hangs or needs a TTY'
Try / catch
match run_auth_flow(...).await {
Err(e) if e.to_string().contains("timed out after 300s") => {
eprintln!("Provider hung; run it manually to find the blocking step, then retry");
}
other => other?,
} Prevention
- Make the provider fail fast instead of waiting on input
- Use device-code or pre-fetched tokens in headless environments
- Ensure the OAuth callback port is free
- Add provider-side internal timeouts well below 300s
When it happens
Trigger: Running any auth flow with an external provider whose process runs longer than 300 seconds: it blocks on an interactive prompt that never gets input (e.g. a browser-based or stdin-based handshake with no TTY), or is simply stuck.
Common situations: Non-interactive/CI runs where the provider waits for a browser OAuth callback that never arrives; provider waiting on stdin with no TTY; network stall inside the provider; provider hangs opening a port already in use for the callback.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- external auth provider `{command}` IO error: {e}
- command timed out after {}s
- failed to start auth provider `{command}`: {e}
- external auth provider `{command}`: {e}
- produced non-UTF-8 output on stdout
AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31).
Data as JSON: /api/errors/9c45910169b9f4fd.
Report an issue: GitHub.