{"record":{"id":"ad21d9ade72ed942","repo":"zeroclaw-labs/zeroclaw","slug":"openai-codex-auth-profile-is-not-oauth-based-pro","errorCode":null,"errorMessage":"OpenAI Codex auth profile is not OAuth-based: {profile_id}","messagePattern":"OpenAI Codex auth profile is not OAuth-based: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/auth/mod.rs","lineNumber":215,"sourceCode":"        Ok(credential.filter(|t| !t.trim().is_empty()))\n    }\n\n    pub async fn get_valid_openai_access_token(\n        &self,\n        profile_override: Option<&str>,\n    ) -> Result<Option<String>> {\n        let data = self.store.load().await?;\n        let Some(profile_id) = select_profile_id(&data, OPENAI_CODEX_PROVIDER, profile_override)\n        else {\n            return Ok(None);\n        };\n\n        let Some(profile) = data.profiles.get(&profile_id) else {\n            return Ok(None);\n        };\n\n        let Some(token_set) = profile.token_set.as_ref() else {\n            anyhow::bail!(\"OpenAI Codex auth profile is not OAuth-based: {profile_id}\");\n        };\n\n        if !token_set.is_expiring_within(Duration::from_secs(OPENAI_REFRESH_SKEW_SECS)) {\n            return Ok(Some(token_set.access_token.clone()));\n        }\n\n        let Some(refresh_token) = token_set.refresh_token.clone() else {\n            return Ok(Some(token_set.access_token.clone()));\n        };\n\n        let refresh_lock = refresh_lock_for_profile(&profile_id);\n        let _guard = refresh_lock.lock().await;\n\n        // Re-load after waiting for lock to avoid duplicate refreshes.\n        let data = self.store.load().await?;\n        let Some(latest_profile) = data.profiles.get(&profile_id) else {\n            return Ok(None);\n        };","sourceCodeStart":197,"sourceCodeEnd":233,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/auth/mod.rs#L197-L233","documentation":"get_valid_openai_access_token selected a profile for openai-codex, but the profile has no token_set — its credential was stored as a plain bearer token (AuthProfileKind::Token, created by auth paste-token / setup-token) rather than an OAuth token set. The function's contract is to return a refreshable OAuth access token, so a token-kind profile is a hard error rather than a None.","triggerScenarios":"Calling resolve_credentials or refresh_status for openai-codex after the active profile was created with auth paste-token (token kind); importing or hand-editing an auth profile file so token_set is null while kind stays OAuth.","commonSituations":"User pasted an API key for codex, then ran an operation that requires the OAuth flow; profile file migrated or edited and the token_set field was dropped; wrong profile selected via profile_override.","solutions":["Run auth login --model-provider openai-codex (browser or --device-code) to store a real OAuth token set for that profile","Or import existing credentials: auth login --model-provider openai-codex --import ~/.codex/auth.json","If a bearer token is intended, use get_provider_bearer_token instead of get_valid_openai_access_token"],"exampleFix":"// before\nlet token = auth.get_valid_openai_access_token(None).await?; // errors on token-kind profile\n\n// after\nlet token = match auth.get_valid_openai_access_token(None).await {\n    Ok(t) => t,\n    Err(e) if e.to_string().contains(\"not OAuth-based\") => {\n        auth.get_provider_bearer_token(\"openai-codex\", None).await?.flatten()\n    }\n    Err(e) => return Err(e),\n};","handlingStrategy":"validation","validationCode":"// Verify the selected profile is OAuth-based before asking for a valid token.\nlet data = auth.load_profiles().await?;\nif let Some(profile) = data.profiles.get(&format!(\"openai-codex:{}\", name)) {\n    anyhow::ensure!(profile.token_set.is_some(), \"profile {name} is a bearer token, not OAuth\");\n}\nlet token = auth.get_valid_openai_access_token(Some(name)).await?;","typeGuard":"fn is_oauth_profile(p: &AuthProfile) -> bool {\n    p.token_set.is_some()\n}","tryCatchPattern":"match auth.get_valid_openai_access_token(override_).await {\n    Ok(tok) => tok,\n    Err(e) if e.to_string().contains(\"not OAuth-based\") => {\n        // credential was stored as a bearer token; either re-login or use the bearer path\n        auth.get_provider_bearer_token(\"openai-codex\", override_).await?.flatten()\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Create codex profiles with auth login (or --import) when OAuth refresh is required","Check profile.token_set.is_some() before calling the OAuth resolver","Use get_provider_bearer_token for paste-token profiles"],"tags":["auth","oauth","openai-codex","profile","rust"],"backgroundTag":"auth-profile-not-oauth","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}