Hmbown/CodeWhale · error · anyhow::Error

xAI OAuth credentials not found. Options: 1. Run `codewhale

Error message

xAI OAuth credentials not found.
Options:
1. Run `codewhale auth xai-device` for Codewhale-owned OAuth storage
2. To read an existing Grok CLI login without changing it, run `codewhale auth external-consent --provider xai --mode read-only --path {}`
3. Or use API-key auth: export XAI_API_KEY=... / codewhale auth set --provider xai

What it means

Emitted from xai_oauth::missing_auth_message() (crates/tui/src/xai_oauth.rs:776) when xAI auth_mode = "oauth" (or Grok CLI tokens exist) but no usable OAuth credential is found: no Codewhale-owned device-login storage and no read-only consent for the Grok CLI auth file (its path is interpolated). It offers three exits: the Codewhale-owned device flow, read-only reuse of a Grok CLI login, or plain API-key auth.

Source

Thrown at crates/tui/src/config.rs:6418

                    provider_config_table_name(provider)?
                );
            }
            ApiProvider::Anthropic | ApiProvider::Openmodel => {
                anyhow::bail!("{}", missing_provider_api_key_message(provider)?)
            }
            ApiProvider::OpencodeZen => {
                anyhow::bail!("{}", missing_provider_api_key_message(provider)?)
            }
            ApiProvider::OpenaiCodex => anyhow::bail!("{}", crate::oauth::missing_auth_message()),
            ApiProvider::Xai => {
                // Prefer OAuth guidance when auth_mode requests it or Grok CLI
                // tokens already exist; otherwise show both API-key and OAuth.
                if self
                    .provider_config_for(provider)
                    .is_some_and(provider_config_uses_xai_oauth)
                    || crate::xai_oauth::credentials_present(self)
                {
                    anyhow::bail!("{}", crate::xai_oauth::missing_auth_message());
                }
                anyhow::bail!(
                    "xAI API key not found. Get a key: https://console.x.ai/\n\
                     Run 'codewhale auth set --provider xai', set XAI_API_KEY, or add \
                     [providers.xai] api_key.\n\
                     OAuth alternative: run `codewhale auth xai-device` for \
                     Codewhale-owned storage and set [providers.xai] auth_mode = \"oauth\"."
                );
            }
            // Self-hosted deployments commonly run without auth on localhost.
            // Return an empty key and let the client omit the Authorization header.
            ApiProvider::Sglang | ApiProvider::Vllm => Ok(String::new()),
            ApiProvider::Ollama
                if provider_route_is_keyless_self_hosted(provider, &self.deepseek_base_url()) =>
            {
                Ok(String::new())
            }
            ApiProvider::Ollama => {

View on GitHub (pinned to 8880682c63)

Solutions

  1. Run codewhale auth xai-device to create Codewhale-owned OAuth storage.
  2. Or grant read-only reuse of the existing Grok CLI login: codewhale auth external-consent --provider xai --mode read-only --path <path from message>.
  3. Or fall back to API keys: export XAI_API_KEY=... or codewhale auth set --provider xai.

Example fix

# before
[providers.xai]
auth_mode = "oauth"   # device flow never completed

# after (terminal)
# codewhale auth xai-device
# or: codewhale auth external-consent --provider xai --mode read-only --path ~/.grok/auth.json
Defensive patterns

Strategy: fallback

Validate before calling

fn xai_oauth_ready(config: &Config) -> bool {
    crate::xai_oauth::credentials_present(config) // Codewhale-owned storage or consented Grok file
        || config
            .provider_config_for(ApiProvider::Xai)
            .is_some_and(provider_config_uses_xai_oauth)
            && crate::xai_oauth::credentials_present(config)
}

if !xai_oauth_ready(&config) && !env_nonempty("XAI_API_KEY") {
    // fall back to API-key route or prompt `codewhale auth xai-device`
}

Type guard

fn xai_auth_path_available(config: &Config) -> bool {
    xai_oauth_ready(config) || env_nonempty("XAI_API_KEY")
}

Try / catch

match config.deepseek_api_key() {
    Err(e) if e.to_string().starts_with("xAI OAuth credentials not found") => {
        // fall back to API-key auth: export XAI_API_KEY / codewhale auth set --provider xai,
        // or complete `codewhale auth xai-device` and retry
        Err(e)
    }
    other => other,
}

Prevention

When it happens

Trigger: [providers.xai] auth_mode = "oauth" with the device flow never run; a Grok CLI login present at the interpolated path but external-consent never granted; OAuth storage cleared by logout.

Common situations: Switching xAI from API key to OAuth without completing `codewhale auth xai-device`; expecting Grok CLI logins to be picked up automatically (they are opt-in via consent).

Related errors


AI-assisted analysis of Hmbown/CodeWhale@8880682c63 (2026-08-16). Data as JSON: /api/errors/92ca64539da91854. Report an issue: GitHub.