fix(codex): adopt refresh_token from auth.json even without access_token - #77028
Merged
kshitijk4poor merged 2 commits intoAug 2, 2026
Conversation
…ken (NousResearch#70097) Two defects in the openai-codex credential pool recovery path: Defect 1 — adoption path silently no-ops when store_access is empty _sync_codex_entry_from_auth_store() skipped adoption when the auth store had no access_token (only last_refresh). When another process rotated the token pair, the stale profile's entry kept the consumed refresh_token and replayed it, getting refresh_token_reused and going terminally DEAD. Fix: also adopt when store_refresh differs from entry_refresh, even when store_access is empty. Keep the entry's existing access_token in that case (store_access or entry.access_token). Defect 2 — false 'auth refreshed' success log _try_refresh_codex_client_credentials() returned True whenever resolve_codex_runtime_credentials() returned any non-empty credentials, including the same stale token when the underlying refresh failed. The conversation loop then logged 'auth refreshed after 401' right before the retry failed with the identical token_expired. Fix: compare the access token before/after the refresh. If unchanged, return False so the 401-retry path logs the truth. Fixes NousResearch#70097
The _sync_codex_entry_from_auth_store source guard returned early for source='manual:device_code', which is the recommended quarantine-safe configuration (hermes auth add openai-codex produces SOURCE_MANUAL_DEVICE_CODE). The PR's fix for refresh_token adoption was unreachable for these entries. Widen the guard to accept both 'device_code' and 'manual:device_code'. Follow-up to NousResearch#70111. Issue reporter (imgyf) confirmed this caused a 12-of-16 fleet outage on Aug 1. Co-authored-by: imgyf <imgyf@users.noreply.github.com>
kshitijk4poor
enabled auto-merge (rebase)
August 2, 2026 18:53
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Codex credential pool profiles go terminally DEAD when a sibling profile rotates the shared token pair — the adoption path silently no-ops when auth.json has a refresh_token but no access_token, and the 401-retry path falsely logs "auth refreshed" when no new token was minted.
Changes
agent/credential_pool.py: Adopt refresh_token from auth.json even whenstore_accessis empty (preserve entry's existing access_token viastore_access or entry.access_token)agent/credential_pool.py: Widen source guard to includemanual:device_codeentries (follow-up commit — the original PR's fix was unreachable formanual:device_code, the recommended quarantine-safe config)run_agent.py: Return False from_try_refresh_codex_client_credentialswhen the refresh produced the same token (compare before/after)Validation
device_codeandmanual:device_codesourcesCloses #70097
Credits @JonthanaHanh for the original fix and @imgyf for the source guard analysis.