Uh oh!
There was an error while loading. Please reload this page.
fix(codex): recover turns after usage limits - #7308
Conversation
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| return; | ||
| } | ||
| const resumedSession = yield* startSessionInternal( |
There was a problem hiding this comment.
🟠 HighLayers/CodexAdapter.ts:1965
A stale usage-limit recovery can stop a newer manual session and leave the thread with no active session. recoverUsageLimitTurn calls startSessionInternal before validating that input.token is still current; if startSession has already deleted the token and installed a replacement, the recovery replaces and then stops that replacement, and finally closes its own runtime. Validate the token before replacing the registered session and atomically guard the replacement.
🤖 Copy this AI Prompt to have your agent fix this:
In file @apps/server/src/provider/Layers/CodexAdapter.ts around line 1965:
A stale usage-limit recovery can stop a newer manual session and leave the thread with no active session. `recoverUsageLimitTurn` calls `startSessionInternal` before validating that `input.token` is still current; if `startSession` has already deleted the token and installed a replacement, the recovery replaces and then stops that replacement, and finally closes its own runtime. Validate the token before replacing the registered session and atomically guard the replacement.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want fixes drafted automatically? Bugbot Autofix can create code changes for findings. A team admin can enable Autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 92a148c. Configure here.
| failedTurnId: input.failedTurnId, | ||
| }, | ||
| ); | ||
| return; |
There was a problem hiding this comment.
Aborted recovery leaves session open
Medium Severity
When post-resume readThread finds provider activity on the failed turn, recoverUsageLimitTurn returns without calling stopSessionInternal. By then startSessionInternal has already stopped the original session and registered the recovery process. Sibling abort paths for wrong thread or model do close that session. An account-selecting executable can therefore leave the thread on a replaced process after refusing to retry, instead of closing the recovery session and surfacing the original usage-limit failure.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit 92a148c. Configure here.
ApprovabilityVerdict: Needs human review 1 blocking correctness issue found. This PR introduces a new automatic recovery feature for usage-limit failures with significant state management complexity (recovery tokens, pending turn tracking, deferred completions). A High-severity finding identifies a potential race condition where stale recovery can interfere with newer sessions. You can customize Macroscope's approvability policy. Learn more. |


Decision
Codex App Server keeps one account per process, so a T3 thread stops when that account runs out. This change restarts the configured executable, strictly resumes the same provider thread, and retries a safe failed turn once. Account-selecting launchers can then continue the conversation with available quota. Other providers, contracts, clients, and UI behavior do not change.
What Changed
usageLimitExceededcompletion emitted by Codex App Server.Production Behavior And Risk
The recovery path runs only for the first usage-limit failure. It refuses to retry after assistant output, tool requests, commands, hooks, diffs, plans, collaboration activity, or queued turns. It verifies the resumed provider thread and requested model before retrying.
Manual session starts, stops, and interrupts cancel an in-flight recovery. A recovery process cannot overwrite a newer user-started session. A second usage-limit failure remains visible and does not launch a third process.
The worst case is a configured executable that restarts but cannot resume the original provider thread. T3 Code closes that recovery session and exposes the existing failure. It never creates a disconnected conversation. T3 Code adds no migrations or new persistent state. Its only provider mutation is rolling back the failed user-only turn before retrying it.
Reviewer Focus
turn/completedarrives before theturn/startresponse.Test Plan
vp test run apps/server/src/provider/Layers/CodexAdapter.test.ts apps/server/src/provider/Layers/CodexSessionRuntime.test.ts— 57 tests passed.vp lintfor the four changed TypeScript files.vp run --filter t3 typecheck— passed with existing suggestions in unrelated files.vp fmt --checkfor all five changed files.Checklist
Built with GPT-5.6 Sol in Codex.
Note
Medium Risk
Changes Codex session lifecycle (process restart, thread resume, rollback, and async recovery) on a critical provider path, but scope is narrow with fail-closed guards and extensive tests.
Overview
Codex now handles
usageLimitExceededturn failures by giving account-selecting launchers one automatic retry without leaving the conversation.When a turn fails with that error and produced no assistant/tool activity (only user-message lifecycle events are allowed), the adapter restarts the configured Codex process, opens the session with
requireResumesothread/resumecannot fall back to a fresh thread, verifies the same provider thread and model, optionally rolls back a user-only failed turn, then re-sends the exact prompt once. The original failure still flows through the event stream; a second limit hit is not retried again.Guards and races: pending-turn tracking handles
turn/completedarriving beforeturn/start;unsafeTurnIdsblocks retry after any real provider output (including items only on completion); queued turns, manualstartSession/stopSession/interruptTurn, and in-flight recovery use recovery tokens so recovery cannot replace a newer user session.sendTurnis rejected while recovery is active.Tests cover happy path, race with manual session start, no-retry with activity, and strict resume behavior. User docs describe when auto-recovery runs and when it stops.
Reviewed by Cursor Bugbot for commit 92a148c. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Add automatic recovery from usage-limit failures in
CodexAdapterusageLimitExceededand no provider activity has occurred in that turn, the adapter automatically restarts the runtime, resumes the same thread, and retries the turn exactly once.requireResumeflag inCodexSessionRuntimeOptionsprevents fallback to a fresh thread when strict resume is required; recoverable resume errors are surfaced instead of silently starting over.sendTurnis blocked while recovery is in progress or a recovery token is active; tokens are cleared on explicit starts, interrupts, and stops.TestQueueutilities for deterministic event ordering.📊 Macroscope summarized 92a148c. 3 files reviewed, 0 issues evaluated, 0 issues filtered, 0 comments posted
🗂️ Filtered Issues
No issues evaluated.