Hmbown/CodeWhale · error

xAI OAuth credentials at

Error message

xAI OAuth credentials at {} have no usable entry. Run `grok login` again or use `codewhale auth xai-device` for Codewhale-owned storage.

What it means

validate_grok_external_credentials reads the Grok CLI's auth file under a consented ExternalCredentialReadGrant and calls select_entry to pick a usable xAI credential entry. If no entry in the external file is usable for xAI (missing, wrong provider shape, or empty), this error tells the user to re-authenticate with Grok or switch to Codewhale-owned storage.

Solutions

  1. Run `grok login` again to write fresh xAI credentials.
  2. Prefer Codewhale-owned storage: run `codewhale auth xai-device`.
  3. Verify the file at the quoted path actually contains xAI tokens (not another provider's).
Defensive patterns

Strategy: validation

Validate before calling

if (!fs.existsSync(grantPath) || !fs.readFileSync(grantPath,'utf8').includes('access_token')) await grokLogin();

Type guard

const hasUsableEntry = (file) => Object.values(file?.entries ?? {}).some(e => e?.access_token);

Try / catch

try { validateGrokExternal(grant); } catch (e) { if (String(e).includes('no usable entry')) await xaiDeviceAuth(); }

Prevention

When it happens

Trigger: Calling validate_grok_external_credentials when the Grok CLI auth file at grant.path() contains no entry that select_entry can accept for OAuthProvider::Xai.

Common situations: User never ran `grok login`; grok CLI updated and changed its auth-file format; user logged into grok with a non-xAI account; the file was cleared by the CLI's logout.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/01a0517c96d4c9a0. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/oauth.rs:2096

}

#[must_use]
pub fn credentials_present(provider: OAuthProvider, config: &Config) -> bool {
    credentials_valid(provider, config)
}

/// Grant-time validation for an external Grok CLI credential file (#5772).
///
/// Reads exactly the granted path through the secure adapter and requires a
/// usable, unexpired entry. Never refreshes, rewrites, or makes a network
/// request. Consent is persisted only after this succeeds, so a consent
/// record can never be written for a file that holds nothing usable.
pub fn validate_grok_external_credentials(
    grant: &codewhale_config::ExternalCredentialReadGrant,
) -> Result<()> {
    let mut file = load_external_auth_file(grant)?;
    let (_, entry) = select_entry(OAuthProvider::Xai, &mut file).ok_or_else(|| {
        anyhow::anyhow!(
            "xAI OAuth credentials at {} have no usable entry. Run `grok login` again or use `codewhale auth xai-device` for Codewhale-owned storage.",
            codewhale_config::quote_os_path(grant.path())
        )
    })?;
    if !entry_access_token_is_fresh(&entry) {
        bail!(
            "xAI OAuth access token in {} is expired. Read-only consent never refreshes or rewrites another CLI's credentials. Run `grok login` again or use `codewhale auth xai-device`.",
            codewhale_config::quote_os_path(grant.path())
        );
    }
    Ok(())
}

/// Load xAI OAuth credentials with full precedence: configured generation,
/// legacy owned file, then the consented Grok CLI import. Codewhale-owned
/// credentials may refresh and rewrite Codewhale-owned storage; external
/// credentials are read-only.
pub fn get_xai_credentials(config: &Config) -> Result<OwnedOAuthCredentials> {

View on GitHub (pinned to 73e0f67d83)