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

  1. Run the provider command manually with the same inputs to see where it blocks; fix the provider's blocking step.
  2. For headless environments, configure the provider for non-interactive mode (device-code flow or pre-fetched token).
  3. Check the callback port is not occupied and that browsers/loopback access works if the provider waits for an OAuth redirect.
  4. 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

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

Related errors


AI-assisted analysis of xai-org/grok-build@bc7f02eddd (2026-08-31). Data as JSON: /api/errors/9c45910169b9f4fd. Report an issue: GitHub.