{"record":{"id":"92ca64539da91854","repo":"Hmbown/CodeWhale","slug":"xai-oauth-credentials-not-found-options-1-run","errorCode":null,"errorMessage":"xAI OAuth credentials not found.\nOptions:\n1. Run `codewhale auth xai-device` for Codewhale-owned OAuth storage\n2. To read an existing Grok CLI login without changing it, run `codewhale auth external-consent --provider xai --mode read-only --path {}`\n3. Or use API-key auth: export XAI_API_KEY=... / codewhale auth set --provider xai","messagePattern":"xAI OAuth credentials not found\\.\nOptions:\n1\\. Run `codewhale auth xai-device` for Codewhale-owned OAuth storage\n2\\. To read an existing Grok CLI login without changing it, run `codewhale auth external-consent --provider xai --mode read-only --path (.+?)`\n3\\. Or use API-key auth: export XAI_API_KEY=\\.\\.\\. / codewhale auth set --provider xai","errorType":"console","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/config.rs","lineNumber":6418,"sourceCode":"                    provider_config_table_name(provider)?\n                );\n            }\n            ApiProvider::Anthropic | ApiProvider::Openmodel => {\n                anyhow::bail!(\"{}\", missing_provider_api_key_message(provider)?)\n            }\n            ApiProvider::OpencodeZen => {\n                anyhow::bail!(\"{}\", missing_provider_api_key_message(provider)?)\n            }\n            ApiProvider::OpenaiCodex => anyhow::bail!(\"{}\", crate::oauth::missing_auth_message()),\n            ApiProvider::Xai => {\n                // Prefer OAuth guidance when auth_mode requests it or Grok CLI\n                // tokens already exist; otherwise show both API-key and OAuth.\n                if self\n                    .provider_config_for(provider)\n                    .is_some_and(provider_config_uses_xai_oauth)\n                    || crate::xai_oauth::credentials_present(self)\n                {\n                    anyhow::bail!(\"{}\", crate::xai_oauth::missing_auth_message());\n                }\n                anyhow::bail!(\n                    \"xAI API key not found. Get a key: https://console.x.ai/\\n\\\n                     Run 'codewhale auth set --provider xai', set XAI_API_KEY, or add \\\n                     [providers.xai] api_key.\\n\\\n                     OAuth alternative: run `codewhale auth xai-device` for \\\n                     Codewhale-owned storage and set [providers.xai] auth_mode = \\\"oauth\\\".\"\n                );\n            }\n            // Self-hosted deployments commonly run without auth on localhost.\n            // Return an empty key and let the client omit the Authorization header.\n            ApiProvider::Sglang | ApiProvider::Vllm => Ok(String::new()),\n            ApiProvider::Ollama\n                if provider_route_is_keyless_self_hosted(provider, &self.deepseek_base_url()) =>\n            {\n                Ok(String::new())\n            }\n            ApiProvider::Ollama => {","sourceCodeStart":6400,"sourceCodeEnd":6436,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/8880682c63083a91624de936797efa3ce9e498fd/crates/tui/src/config.rs#L6400-L6436","documentation":"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.","triggerScenarios":"[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.","commonSituations":"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).","solutions":["Run codewhale auth xai-device to create Codewhale-owned OAuth storage.","Or grant read-only reuse of the existing Grok CLI login: codewhale auth external-consent --provider xai --mode read-only --path <path from message>.","Or fall back to API keys: export XAI_API_KEY=... or codewhale auth set --provider xai."],"exampleFix":"# before\n[providers.xai]\nauth_mode = \"oauth\"   # device flow never completed\n\n# after (terminal)\n# codewhale auth xai-device\n# or: codewhale auth external-consent --provider xai --mode read-only --path ~/.grok/auth.json","handlingStrategy":"fallback","validationCode":"fn xai_oauth_ready(config: &Config) -> bool {\n    crate::xai_oauth::credentials_present(config) // Codewhale-owned storage or consented Grok file\n        || config\n            .provider_config_for(ApiProvider::Xai)\n            .is_some_and(provider_config_uses_xai_oauth)\n            && crate::xai_oauth::credentials_present(config)\n}\n\nif !xai_oauth_ready(&config) && !env_nonempty(\"XAI_API_KEY\") {\n    // fall back to API-key route or prompt `codewhale auth xai-device`\n}","typeGuard":"fn xai_auth_path_available(config: &Config) -> bool {\n    xai_oauth_ready(config) || env_nonempty(\"XAI_API_KEY\")\n}","tryCatchPattern":"match config.deepseek_api_key() {\n    Err(e) if e.to_string().starts_with(\"xAI OAuth credentials not found\") => {\n        // fall back to API-key auth: export XAI_API_KEY / codewhale auth set --provider xai,\n        // or complete `codewhale auth xai-device` and retry\n        Err(e)\n    }\n    other => other,\n}","preventionTips":["Finish `codewhale auth xai-device` before setting auth_mode = \"oauth\".","Grok CLI logins are opt-in: grant external-consent to reuse them read-only.","Keep an XAI_API_KEY fallback configured while setting up OAuth."],"tags":["rust","xai","oauth","device-flow","external-consent","credentials"],"backgroundTag":null,"analyzedSha":"8880682c63083a91624de936797efa3ce9e498fd","analyzedAt":"2026-08-16T11:31:27.956Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}