Hmbown/CodeWhale · error

Codewhale-owned xAI OAuth credentials are inactive until…

Error message

Codewhale-owned xAI OAuth credentials are inactive until the xAI route explicitly selects OAuth

What it means

get_xai_credentials refuses to load Codewhale-owned xAI OAuth credentials unless the active API provider is Xai AND that provider's config explicitly selects an xAI-OAuth auth_mode (checked with auth_mode_uses_xai_oauth). This prevents silently using stored OAuth tokens when the route is configured for API-key auth or a different provider.

Solutions

  1. Set the xAI provider entry's auth_mode to the OAuth mode in your Codewhale config (or re-run `codewhale auth xai-device`, which configures it).
  2. If you intend API-key auth, stop relying on OAuth credentials and supply an API key instead.
  3. Check that the active route actually selects ApiProvider::Xai.

Example fix

// before (config)
[xai]
auth_mode = "api_key"
// after
[xai]
auth_mode = "oauth"  # the xAI-OAuth auth mode accepted by auth_mode_uses_xai_oauth
Defensive patterns

Strategy: validation

Validate before calling

if (cfg.api_provider !== 'xai' || !/^oauth/.test(cfg.providers?.xai?.auth_mode ?? '')) fixAuthMode(cfg);

Type guard

const xaiOauthActive = (cfg) => cfg.api_provider === 'xai' && typeof cfg.providers?.xai?.auth_mode === 'string' && cfg.providers.xai.auth_mode.includes('oauth');

Try / catch

try { getXaiCredentials(); } catch (e) { if (String(e).includes('inactive until the xAI route')) updateConfigAuthMode('oauth'); }

Prevention

When it happens

Trigger: Calling get_xai_credentials when config.api_provider() != ApiProvider::Xai, or when provider_config_for(Xai).auth_mode is absent or not an xAI-OAuth mode (e.g. "api_key" or unset).

Common situations: User completed `codewhale auth xai-device` but the xAI route in config still specifies api_key auth_mode; config file edited to remove auth_mode; credentials carried over from an experiment while the route points elsewhere.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

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

            "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> {
    anyhow::ensure!(
        config.api_provider() == crate::config::ApiProvider::Xai
            && config
                .provider_config_for(crate::config::ApiProvider::Xai)
                .and_then(|entry| entry.auth_mode.as_deref())
                .is_some_and(auth_mode_uses_xai_oauth),
        "Codewhale-owned xAI OAuth credentials are inactive until the xAI route explicitly selects OAuth"
    );
    if let Some(owned_path) = configured_owned_auth_file_path(OAuthProvider::Xai, config)? {
        return get_owned_credentials_at(OAuthProvider::Xai, &owned_path);
    }
    let owned_path = codewhale_config::legacy_xai_oauth_path()?;
    if load_owned_auth_file(&owned_path)?.is_some() {
        return get_owned_credentials_at(OAuthProvider::Xai, &owned_path);
    }

    let external_path = grok_auth_file_path();
    let grant = config.external_credential_read_grant(
        crate::config::ApiProvider::Xai,

View on GitHub (pinned to 73e0f67d83)