Note
Grok responding on behalf of Julius.
Triage
Thanks for the report, @fedesimio! The difference from the earlier reports (a single long run, not a later turn) helps a lot.
What I found (on main, 43f8a8de1)
With managed ChatGPT sign-in, the Codex app-server process seems to get one access token when it launches and has no way to receive a newer one while it runs.
makeCodexManagedRuntimeputs the current access token into the app-server's launch environment, and the managed model provider reads it from there (CodexManagedRuntime.ts#L25, L67, L91-L95). T3 keeps the refresh token in its own credential store; Codex itself does not appear to refresh in this mode.CodexAdapterV2.openSessionresolves that runtime once per session and spawns the app-server with it (CodexAdapterV2.ts#L1696-L1717), andProviderSessionManagerreuses the live session afterwards (ProviderSessionManager.ts#L2038-L2058).CodexChatGptAuth.accessonly renews when the saved token has less than 60 seconds left; otherwise it hands back the saved token as is (CodexChatGptAuth.ts#L734-L735). So a session opened, or reopened after a restart or reconnect, can start with whatever lifetime the saved token has left. That would fit a failure time that varies between runs and comes back after a restart.- I found no timer that renews the token during a running turn, and no handling of a mid-turn
401that renews and retries. The app-server protocol has anaccount/chatgptAuthTokens/refreshserver request (reasonunauthorized) (meta.gen.ts#L127), but the adapter does not register a handler for it, and it may only apply to Codex's external ChatGPT auth mode rather than the token-sharing provider used here.
Related
- #16132 (open) shares the root cause: the process keeps its launch token. That report covers the next turn failing after T3 renews the token; here a single run outlives the token. Not a duplicate, but likely one fix area.
- #16849 (open, has merge conflicts) fixes #16132 by releasing an idle session whose token was renewed, so the next turn relaunches. It skips sessions with a running turn, and its PR description notes that a turn already running at expiry can still fail with
401. It might make the "continue" step recover, but on its own it probably would not keep a long run alive. - #14356 (open) covers the renewal request itself failing with
invalid_grant. You did not see that error, so it may not be involved, though it could add to the failures if renewal also fails.
Possible directions (unverified)
- Before starting a turn, renew the token when its remaining lifetime falls below a larger margin, and relaunch the session with the new token (builds on #16849). This would lengthen runs but stays capped by the token's lifetime.
- Let a running app-server receive fresh tokens, for example through Codex's external ChatGPT auth (
account/login/startwithchatgptAuthTokensplus a handler foraccount/chatgptAuthTokens/refresh), if that can work with the token-sharing provider. - As a fallback, on a mid-turn
token_expired, renew, relaunch, and resume the native thread automatically.
If you can share the T3 server log lines around a failure (with tokens redacted), especially any chatgpt./refresh entries, that would help show whether renewal ran and succeeded before the run failed.