xai-org/grok-build · error

failed to save external auth credentials: {e}

Error message

failed to save external auth credentials: {e}

What it means

After a successful external provider run and inline enrichment, auth_manager.update(auth) persists the new credentials to the auth store. If persistence fails (file write, keyring, or storage backend error), the freshly obtained credentials cannot be saved and this error aborts the login. The user authenticated but the session was not stored.

Source

Thrown at crates/codegen/xai-grok-shell/src/auth/flow.rs:260

    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)
        .await
        .map_err(|e| anyhow::anyhow!("failed to save external auth credentials: {e}"))?;
    tracing::info!(
        user_id = %auth.user_id,
        email = ?auth.email,
        "auth: external provider login complete"
    );
    Ok((auth, true))
}
/// GUI auth: bridges external provider stderr to `url_tx`, pipes code submission via `code_rx`.
pub(crate) async fn run_auth_flow_with_stderr_bridge(
    auth_manager: &Arc<AuthManager>,
    grok_com_config: &GrokComConfig,
    channels: AuthChannels,
    reauth: bool,
    force_interactive: bool,
    login_override: LoginTransportOverride,
) -> anyhow::Result<(GrokAuth, bool)> {
    let url_tx = Rc::new(RefCell::new(channels.url_tx));
    let stderr_lines: Rc<RefCell<Vec<String>>> = Rc::new(RefCell::new(Vec::new()));

View on GitHub (pinned to bc7f02eddd)

Solutions

  1. Check writability of the grok home directory (`ls -ld`, try touching a file) and fix permissions/ownership.
  2. Free disk space if the filesystem is full.
  3. On headless Linux, install/unlock a secret service (gnome-keyring) or configure a file-based auth store.
  4. Back up and remove a corrupted auth store file so update() can recreate it, then log in again.

Example fix

// before
chmod 555 ~/.grok   # store not writable
// after
chmod 700 ~/.grok && chown -R $USER ~/.grok
Defensive patterns

Strategy: try-catch

Validate before calling

const home = process.env.GROK_HOME || '~/.grok';
fs.accessSync(home, fs.constants.W_OK); // throws early if store dir is unwritable

Try / catch

match run_auth_flow(...).await {
    Err(e) if e.to_string().contains("failed to save external auth credentials") => {
        eprintln!("Login succeeded but saving failed — check disk space, ~/.grok permissions, keyring");
    }
    other => other?,
}

Prevention

When it happens

Trigger: update() returns Err during any external-provider login because the auth store is unwritable: bad permissions on the grok home directory, disk full, keyring/secret-service unavailable, or a corrupted existing auth store.

Common situations: Read-only home or NFS mount in CI containers; full disk; headless Linux without a keyring/secret service; corrupted ~/.grok auth file from a previous crash; SELinux/AppArmor denying writes.

Related errors


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