Skip to content

fix(codex): show neutral wording for exhausted HTTP 429 retries - #26532

Open
samaluk wants to merge 4 commits into
pingdotgg:mainfrom
samaluk:fix/codex-429-limit-wording-24885
Open

samaluk wants to merge 4 commits into
pingdotgg:mainfrom
samaluk:fix/codex-429-limit-wording-24885

Conversation

@samaluk

@samaluk samaluk commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Problem

Fixes #24885.

Codex can reduce an upstream HTTP 429 to responseTooManyFailedAttempts with exceeded retry limit, last status: 429 Too Many Requests. T3 deliberately routes that failure through usage_limit recovery, but its Usage limit reached explanation treats an ambiguous rate limit as exhausted allowance. Codex has already discarded the upstream reason; T3 cannot infer capacity or quota exhaustion from that status alone (openai/codex#30471).

Change

Use one shared title decision for the existing failure class and code. Exhausted Codex HTTP 429 retries say Provider rate limit (HTTP 429); explicit usageLimitExceeded failures retain Usage limit reached. Missing-reset guidance says No reset time reported; retry manually.

Apply that decision to new stored terminal/retry items, web/desktop timeline and recovery banners, sidebar tooltips and notifications, and mobile feed, timeline and recovery cards. Clients also correct the displayed title of older items whose stored title still says usage limit. Show the retained provider message in warning rows instead of hiding it.

The adapter classification, Limited state, manual Resume controls, reset timestamps, retry policy and provider/model selection are unchanged. Completed retries keep their recovered presentation. This does not extend #25611's separate handling of explicit serverOverloaded failures or change the ACP ingestion concern mentioned in the issue comments.

Scope and approval

This is a focused correction of an inaccurate explanation on an established recovery path, under CONTRIBUTING.md's exception for a focused obvious bug. The server and client edits address that same explanation; they add no recovery workflow or wire-contract change. The problem and diagnostic-loss constraint are documented in #24885 and its comments. No maintainer approval of a broader behavior change is claimed.

Verification

Linux, Node 26.12.0, Vite+ 1.4.0; base 5211acfe95a0.

  • Added the regressions before production edits: five failures and 99 passing tests. The failures demonstrated the incorrect stored title, web/mobile projection, and recovery-banner wording. After the fix, all 104 tests in those four files passed:
    vp test run packages/provider-core/src/server/failure.test.ts apps/web/src/session-logic.test.ts apps/mobile/src/lib/threadActivity.test.ts apps/web/src/components/chat/UsageLimitRecoveryBanner.test.tsx.
    Coverage distinguishes exhausted 429s from explicit quota errors, preserves provider details/class/reset evidence, handles legacy titles, and keeps recovered retries labeled as recovered.
  • 13 Codex protocol replays passed, including explicit quota versus structured 429/500 exhaustion and completion-status precedence over cached notifications:
    vp test run apps/server/src/orchestration-v2/Adapters/CodexAdapterV2.test.ts -t 'classifies Codex terminal failures|honors completion HTTP status' (run as two focused invocations).
  • 17 existing recovery tests passed, including manual Resume and reset-based recovery guards:
    vp test run apps/server/src/orchestration-v2/runtimeLayer.test.ts -t 'usage-limit recovery'.
  • Ran vp run check:changed with browser/render projects excluded by a temporary subprocess hook outside the repository (Vitest arguments --project '!*browser*' --project '!*renders*'). Format, lint, both knip passes, typechecks of the 31 affected packages/dependents, and 162 tests in eight non-browser files passed. Removed the check runner's result cache afterward so an excluded run cannot be reused as a complete browser-inclusive result. No repository check tooling was changed.

Limitations: browser/computer use was explicitly excluded from this task, so there are no before/after UI screenshots or integrated web/desktop/mobile captures; this does not meet the repository's UI screenshot evidence requirement. An initial attempt to exclude browser files still made Vitest initialize its browser project and failed because Chromium was absent; no browser launched. The final run excluded the projects themselves. No live upstream 429 was induced, and no historical stored-title backfill is included. Diagnostic details that Codex has discarded remain unavailable to T3.

Model: GPT-6.1 Sol, extra-high reasoning, personal profile. Harness: Codex through T3 Code.

@github-actions github-actions Bot added vouch:unvouched Author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Oct 28, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 28, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Approved at ea55947

Macroscope's review found this PR approvable — Exhausted HTTP 429 retries receive neutral provider-rate-limit wording across web and mobile, with the provider’s explanation visible in work logs. Retry and recovery behavior remain unchanged.

You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Walkthrough

A shared title function distinguishes provider errors from usage-limit failures and identifies the responseTooManyFailedAttempts usage-limit code. Server failure items and mobile and web presentations use these titles. Tests cover failure titles, retry labels, and activity summaries.

Changes: Provider failure presentation

Layer / File(s) Summary
Shared failure titles and server items
packages/shared/src/orchestrationV2ThreadError.ts, packages/provider-core/src/server/failure.ts, packages/provider-core/src/server/failure.test.ts
The shared function selects a title based on failure class and code. Terminal and failed-retry items use that title, with tests covering the resulting titles and retained failure data.
Web failure presentations
apps/web/src/session-logic.ts, apps/web/src/session-logic.test.ts, apps/web/src/components/ThreadNotificationCoordinator.tsx, apps/web/src/components/chat/TimelineWorkEntryRow.tsx, apps/web/src/components/chat/UsageLimitRecoveryBanner.tsx, apps/web/src/components/sidebar/SidebarThreadRow.tsx
Web session labels, notifications, timeline rows, banners, and sidebar tooltips use titles based on failure class and code. Warning rows display the failure message. The banner changes its missing-reset description, and tests cover both usage-limit codes.
Mobile failure presentations
apps/mobile/src/features/threads/UsageLimitRecoveryCard.tsx, apps/mobile/src/features/threads/thread-work-log.tsx, apps/mobile/src/lib/threadActivity.ts, apps/mobile/src/lib/threadActivity.test.ts
Mobile recovery and work-log views use titles based on failure class and code. Work-log failure messages appear in row content and accessibility labels. Activity summaries use the derived title, with tests covering failure codes and recovered errors.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix · Severity of issue fixed: Low

Suggested reviewers: t3dotgg, juliusmarminge, maria-rcks

Merge Risk: Minimal · up to fdc03

The change updates wording for exhausted HTTP 429 retries across the server, web and mobile, and no concrete defect is evident in the supplied material. Explicit rate-limit errors still use the old wording, which is a known follow-up and does not block merging.

Pre-merge checks: Passed 4

Check name Status Explanation
Title check Passed The title names the main change: exhausted Codex HTTP 429 retries now show neutral wording instead of the usage-limit text. It is a conventional commit title that matches the changeset, which adds a s…
Description check Passed The description follows the template sections: Problem, Change, Scope, and Verification. It names the issue (#24885), explains the change, gives the scope rationale, and reports detailed test commands…
Linked Issues check Passed Directly linked issue #24885 asks that an ambiguous Codex HTTP 429 not be presented as proof of exhausted usage allowance. It also asks that provider details be preserved, and that manual retry remain…
Out of Scope Changes check Passed All changed files apply the same title decision or the same warning-row message display. The changes cover the server failure item, the shared helper, the web timeline, banner, sidebar, notification, …
Full details: Title check

Explanation

The title names the main change: exhausted Codex HTTP 429 retries now show neutral wording instead of the usage-limit text. It is a conventional commit title that matches the changeset, which adds a shared providerFailureTitle helper and applies it across server, web, and mobile.

Full details: Description check

Explanation

The description follows the template sections: Problem, Change, Scope, and Verification. It names the issue (#24885), explains the change, gives the scope rationale, and reports detailed test commands and results. It also states limitations, including no UI screenshots, which the template requires for UI changes. The missing screenshots are a gap against the template, but the other required sections are substantively complete.

Full details: Linked Issues check

Explanation

Directly linked issue #24885 asks that an ambiguous Codex HTTP 429 not be presented as proof of exhausted usage allowance. It also asks that provider details be preserved, and that manual retry remain available without an invented reset time.

The reproduced failure is responseTooManyFailedAttempts with exceeded retry limit, last status: 429 Too Many Requests. The shared helper providerFailureTitle in packages/shared/src/orchestrationV2ThreadError.ts maps this case to Provider rate limit (HTTP 429). Explicit usageLimitExceeded keeps Usage limit reached. packages/provider-core/src/server/failure.ts applies the title to terminal and failed-retry items and keeps the failure object. The web (session-logic.ts, TimelineWorkEntryRow.tsx, UsageLimitRecoveryBanner.tsx, SidebarThreadRow.tsx, ThreadNotificationCoordinator.tsx) and mobile (threadActivity.ts, thread-work-log.tsx, UsageLimitRecoveryCard.tsx) projections use the same helper. The missing-reset text is now No reset time reported; retry manually. Warning rows show the retained provider message.

Tests in failure.test.ts, session-logic.test.ts, threadActivity.test.ts, and UsageLimitRecoveryBanner.test.tsx cover the ambiguous 429 case, the explicit quota case, retained details, and legacy titles. Manual Resume, reset timestamps, and retry policy are documented as unchanged.

Residual limits: the upstream capacity text (turn_rate_limit_exceeded) is not in the stored failure, so T3 cannot restore that explanation. The issue acknowledges that Codex may discard it. Explicit rateLimitExceeded TPM failures still show Usage limit reached. That case is a separate reported path and is deferred by the PR. Browser and UI verification was not performed, so the rendered wording is supported by unit tests and not by screenshots.

Full details: Out of Scope Changes check

Explanation

All changed files apply the same title decision or the same warning-row message display. The changes cover the server failure item, the shared helper, the web timeline, banner, sidebar, notification, and session logic, and the mobile feed, timeline, and recovery card. Each change supports the correction of the usage-limit explanation described in #24885.

The PR does not add a recovery workflow, automatic retry, wire-contract change, or serverOverloaded handling. The PR states that adapter classification, Limited state, manual Resume, reset timestamps, retry policy, and provider/model selection are unchanged. Test files support the changed behavior. No unrelated change appears in the reviewed summary. The PR also states that no historical backfill is included, and no such backfill appears in the changed files.

Finishing Touches

Generate unit tests (beta)

  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Recent review info

Run configuration

Commits

Reviewing files that changed from the base of the PR and between 9d0b12f and fdc03e3.

Files selected for processing: 11

  • apps/mobile/src/features/threads/UsageLimitRecoveryCard.tsx
  • apps/mobile/src/features/threads/thread-work-log.tsx
  • apps/mobile/src/lib/threadActivity.test.ts
  • apps/mobile/src/lib/threadActivity.ts
  • apps/web/src/components/ThreadNotificationCoordinator.tsx
  • apps/web/src/components/chat/TimelineWorkEntryRow.tsx
  • apps/web/src/components/chat/UsageLimitRecoveryBanner.tsx
  • apps/web/src/components/sidebar/SidebarThreadRow.tsx
  • apps/web/src/session-logic.ts
  • packages/provider-core/src/server/failure.test.ts
  • packages/provider-core/src/server/failure.ts

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

maria-rcks commented Oct 30, 2026 •

Copy link
Copy Markdown
Collaborator

Note

Written by claude-opus-5-5 on behalf of Maria

Takeover update

merged current main into the branch at 9d0b12f855 (merge commit, no rebase). the change's intent and size are unchanged.

  • conflicts were in UsageLimitRecoveryBanner.tsx, its test, and ChatView.tsx. main added a ChatGPT-branded notice and an errorCode prop for the same data this pr passed as failureCode.
  • resolution: kept main's errorCode name and its ChatGPT branch (partner-guideline copy) unchanged. the generic branch now uses providerFailureTitle("usage_limit", errorCode), so exhausted responseTooManyFailedAttempts retries show "Provider rate limit (HTTP 429)". the reset fallback uses this pr's "No reset time reported; retry manually".
  • vp run check:changed passes on a blacksmith testbox: format, lint, knip, typecheck (34 packages), tests (9 files), react compiler.

Not changed

  • explicit rateLimitExceeded (the TPM case reported above) still shows "Usage limit reached". covering it would widen this pr, so it is left for a follow-up.
  • the exhausted-429 ui state is still unverified in a real app. no real 429 was available, same as the earlier note.

Earlier verification (gpt-6.1-sol, at ea55947ac8)

partial verification only. the changed http 429 behavior is unverified.

  • started github/main (32ecd71726) and then the pr with isolated data, one dev server at a time, repo playwright and /usr/bin/google-chrome.
  • created projects pointing at real git checkouts, selected codex gpt-6.1-sol, submitted the same prompt, and saw verification baseline ok. on both revisions. main needed a reload to display its already-persisted answer.
  • on the pr, ran a real codex terminal command (sleep 60), clicked stop, saw Run interrupted · Stopped by user, then saw follow-up after stop ok. in the same thread. persisted run statuses were completed, interrupted, completed.
  • the four changed regression files passed through blacksmith: 104 tests in 4 files.

short provider/server transcript

main, normal provider turn (this does not reproduce the 429 bug):

main real codex answer

pr, matching prompt and answer:

pr real codex answer

shortened capture of the real command, stop and follow-up; sampled frames, not timing evidence:

pr command stop and successful follow-up

not verified then: the original bug on main and the exhausted-429 wording on the pr (the real proxy returned successes, and no mocks or injected errors were used), the limited-state banner, warning row, sidebar tooltip, notification, manual resume, reset scheduling, recovered-retry presentation, desktop electron, native mobile, relay/tunnel, and other operating systems.

@4dwaffle

4dwaffle commented Nov 5, 2026

Copy link
Copy Markdown

Verified an additional case on Windows with T3 0.1.8-nightly.20261104.4165, using Codex through ChatGPT sign-in on a Pro subscription. The user reports 99% of their weekly allowance remaining; I did not independently verify that percentage.

The captured terminal turn/completed error is explicitly a throughput rejection:

codexErrorInfo: rateLimitExceeded
Rate limit reached for gpt-6.1-sol ... on tokens per min (TPM):
Limit 1000000, Used 732209, Requested 360332.
Please try again in 5.552s.

I fetched this PR at ea55947ac8e0f3948ff7ccd400e73b1adc16c87c and executed its exact codexUsageLimitError and providerFailureTitle function bodies against a captured terminal TPM error. It still becomes class: usage_limit with the title Usage limit reached. The added failure.test.ts table explicitly expects that title for rateLimitExceeded; only responseTooManyFailedAttempts receives the neutral rate-limit title.

Could this wording fix also cover explicit rateLimitExceeded? In this incident the provider retains the specific TPM explanation, so the headline can distinguish rate throttling from subscription allowance exhaustion without guessing. Showing the retained message in the timeline is helpful, but the recovery banner and other shared-title consumers would still use the misleading headline.

Verification was limited to executing the PR's classifier/title logic with the captured error and inspecting its web/mobile consumer call sites. No browser test, full adapter replay, or live throttling reproduction was performed. No retry-policy change is requested here.

Posted by Codex (GPT-6.1 Sol) through T3 Code on behalf of the user.

…ording-24885

# Conflicts:
#	apps/web/src/components/ChatView.tsx
#	apps/web/src/components/chat/UsageLimitRecoveryBanner.test.tsx
#	apps/web/src/components/chat/UsageLimitRecoveryBanner.tsx
…ording-24885

# Conflicts:
#	apps/mobile/src/features/threads/UsageLimitRecoveryCard.tsx
#	apps/web/src/components/chat/UsageLimitRecoveryBanner.tsx
AI-assisted; verified with the tests and tools listed above.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:unvouched Author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Codex capacity HTTP 429 is shown as "Usage limit reached" while allowance remains

4 participants