Repository navigation
fix(server): Codex turns that fail with an unlisted error code no longer stay running - #28040
juliusmarminge wants to merge 4 commits into
Conversation
…rror info A Codex turn that completes failed with codexErrorInfo "modelNotFound" (sent by ChatGPT-account Codex when it rejects a model) never reaches turn.terminal: the generated schema's closed CodexErrorInfo union rejects the value, so the error and turn/completed notifications are dropped at decode. This test reproduces #28032 and fails on main. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codex sends codexErrorInfo codes the pinned protocol schema does not list, such as "modelNotFound" when a ChatGPT account rejects a model. The closed literal union failed decode, so the client dropped both the error and the failed turn/completed notifications and the turn stayed running forever. Override CodexErrorInfo in the generator so its string branch accepts any code, keeping the typed struct variants, and regenerate the schema. Fixes #28032 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ing a copy Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ApprovabilityVerdict: Approved at Macroscope's review found this PR approvable — Unknown Codex error codes can reach existing failure handling instead of leaving failed turns running. The change is limited to error-code decoding and preserves existing turn-status and retry rules. You can add or adjust custom eligibility rules. Learn more. |
Thread transfer impact✅ Thread transfer remains within every enforced ceiling.
Baseline: Scenario and decoded snapshot size10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed. |
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Open the error schema and test failed-turn replay packages/effect-codex-app-server/scripts/generate.ts, apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.test.ts |
The generator replaces constrained string variants in CodexErrorInfo with an unconstrained string schema when no definition override applies. The replay test checks that a turn with modelNotFound ends as failed and retains the provider error message. |
Estimated code review effort: 2 (Simple) | ~10 minutes
Change: Bug fix · Severity of issue fixed: Medium
Suggested reviewers: maria-rcks
Merge Risk: 
Minimal · up to 65c7c
-
Unknown Codex error codes can now produce failed turns with the provider message. No merge-blocking issue remains identified.
Pre-merge checks: 
4
-
Full details: Description check
-
Explanation
The description includes the required Problem, Change, Scope and approval, and Verification sections. It provides detailed reproduction steps, implementation details, issue scope, test results, runtime evidence, and known verification limits.
Full details: Linked Issues check
-
Explanation
Issue
#28032requires unsupported Codex model turns to reach a failed terminal state and retain Codex's error message. The PR widens the generatedCodexErrorInfostring branch to accept unlisted codes, updates the generated schema, and adds a regression test formodelNotFoundon botherrorand failedturn/completednotifications. The reported test and package checks pass. The excluded generated path prevents direct inspection of that file, but the change summary and generator update establish the intended generated change.
Full details: Out of Scope Changes check
-
Explanation
The changed generator logic, generated schema, and regression test directly support issue
#28032. The changes preserve typed structured variants and do not introduce unrelated behavior or surface changes.
-
Finishing Touches
-
Generate docstrings
-
- Commit to this branch
- Create a new PR
Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Problem
When Codex fails a turn with a
codexErrorInfocode our generated schema doesn't list, the T3 run staysrunningforever with no error item. A ChatGPT-account Codex rejecting a model sendsmodelNotFound(reported case:gpt-5-codex). Both theerrorand the failedturn/completednotifications fail schema decode, anddispatchNotificationdrops them with "Dropped a Codex App Server notification that failed to decode". The adapter never sees the terminal event. This is not a registration race.Reproduced on main (e5909e5) with the real dev server and the real
codex-cli 0.163.0app-server. Codex's stdout went through a filter that rewrites"codexErrorInfo":"other"to"modelNotFound", which matches the reporter's wire shape. Thent3 thread start <project> "say hi" --provider <that instance> --model gpt-5-codex. The thread was stillrunning50 s after the nativeturn/completed {status: "failed"}. Control: the same flow without the filter (code"other") ends asfailed.Change
CodexErrorInfois a closed list of string codes plus a few structured variants. The generator now widens the string-code branch of the fetched upstream definition to any string (OpenStringEnumDefinitionsinpackages/effect-codex-app-server/scripts/generate.ts), andschema.gen.tsis regenerated from the same pinned ref. The structured variants stay typed. The only generated change isSchema.Literals([...])→Schema.Stringin the 16 copies ofCodexErrorInfo. Adapter consumers already compare codes as strings, so an unknown code is classed as a plain provider error and the run fails with Codex's message.Scope and approval
Fixes #28032
Verification
fails the turn when Codex reports an error info the schema does not list(CodexAdapterV2.test.ts). It replayserror(willRetry: false) then a failedturn/completed, both withcodexErrorInfo: "modelNotFound". On main it fails withexpected undefined to equal 'failed'; it passes on this branch. With"other"it passes on main too, so it isolates the unlisted code.CodexAdapterV2.test.ts123/123,packages/effect-codex-app-servertests pass.vp run check:changedpasses: format, lint, knip, typecheck of 4 packages, tests.node scripts/generate.tsreproduces the committed generated files (apart from the generator's existing 2-line header).error/turn/completedmodelNotFound/failedmodelNotFound/failedstatus: running,activeRunIdset, 50 s laterstatus: failed,activeRunId: null;thread start --waitexits 1 with Codex's messageFilter used as the Codex instance's binary path (scratch, not committed):
Not checked: a live ChatGPT-account Codex. The VM routes Codex through an API proxy, so the failure text above is the proxy's instead of "The 'gpt-5-codex' model is not supported when using Codex with a ChatGPT account." The decode path is the same.
Claude Opus 5.5 (issue lead, red test, implementation) and GPT-6.1 Sol (review) in Claude Code / Codex, through T3 Code.
🤖 Generated with Claude Code