Skip to content

fix(openai): treat credit_balance_exhausted as terminal credit exhaustion - #18770

Merged
diegosouzapw merged 3 commits into
cheaper-inference:release/v3.8.53from
HouMinXi:fix/credit-balance-exhausted
Nov 4, 2026
Merged

diegosouzapw merged 3 commits into
cheaper-inference:release/v3.8.53from
HouMinXi:fix/credit-balance-exhausted

Conversation

@HouMinXi

@HouMinXi HouMinXi commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

What

Adds credit_balance_exhausted to CREDITS_EXHAUSTED_SIGNALS.

Why

Eligible ChatGPT Pro and Business subscriptions receive monthly API credits that need no payment method. When that balance is spent, requests fail with HTTP 429 and error code credit_balance_exhausted (credits guide):

When your free API credit balance runs out: No credits remain → API requests fail with HTTP 429 and error code credit_balance_exhausted.

That code was not in the list. A response carrying only error.code therefore failed to match any signal and fell through to the rate-limit branch, so the account stayed selectable and kept being retried on a short backoff — even though it cannot recover until someone buys credits.

The existing insufficient_quota entry covers the case where the body still carries the older type. It does not cover a body that surfaces only the code, which is the shape the guide documents. Listing the code explicitly makes both shapes terminal.

Testing

tests/unit/credit-balance-exhausted-signal.test.ts, 5 cases:

  • the documented 429 body (code next to the older type) classifies as credits-exhausted
  • the bare {"error":{"code":"credit_balance_exhausted"}} classifies — this is the case that failed before the change
  • mixed casing still matches (the helper lowercases before comparing)
  • a plain rate_limit_exceeded body is not misread as credit exhaustion
  • the signals that were already in the list still classify, so an appended entry cannot shadow them

All 5 fail against the previous list (case 2) or guard against regressions (cases 3-5); the neighbouring suites auth-passthrough-credit-lockout and account-fallback-service stay at 100 passing.

Also in this diff

tests/unit/18633-credit-exhaustion-parks-connection.test.ts is registered in stryker.conf.json too. That file arrived with #18649 and covers both accountFallback.ts and src/sse/services/auth.ts, but was never added to tap.testFiles. check:mutation-test-coverage --strict scans every unit test against the mutated modules and fails on that drift, so any PR adding a covering test hits it — repairing the omission was the only way to land this one.

@HouMinXi
HouMinXi force-pushed the fix/credit-balance-exhausted branch from d0ebf50 to 01b9060 Compare November 2, 2026 16:52
…tion

Eligible ChatGPT Pro and Business subscriptions now receive monthly API
credits that need no payment method. When that balance is spent the
organization's requests fail with HTTP 429 and error code
`credit_balance_exhausted`.

The code was missing from CREDITS_EXHAUSTED_SIGNALS, so a response carrying
only `error.code` fell through to the rate-limit branch. The account stayed
selectable and kept getting retried on a short backoff even though it cannot
recover until someone buys credits.

List it alongside `insufficient_quota`. The separate entry matters because the
credits guide documents the code, not the older type or message, and a body
that omits those would otherwise never reach the terminal branch.

The new test file covers accountFallback.ts, so it is registered in
stryker.conf.json alongside another covering test that cheaper-inference#18649 left out of the
list: the mutation-test-coverage gate compares every covering unit test against
tap.testFiles and fails on the drift, which made it impossible to land this
change without repairing that omission too.

Signed-off-by: Minxi Hou <houminxi@gmail.com>
@HouMinXi
HouMinXi force-pushed the fix/credit-balance-exhausted branch from 01b9060 to 0caac3c Compare November 2, 2026 17:46
@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

No actionable comments were generated in the recent review.

Summary

Summary by CodeRabbit

  • Bug Fixes
    • Credit-balance exhaustion errors are now treated as terminal rather than temporary rate limits, preventing affected accounts from being retried after a short delay.

The shared credit exhaustion signals now include credit_balance_exhausted. Unit tests cover matching and non-matching responses. The Stryker TAP configuration includes the new tests, and the changelog describes the response classification.

Changes: Credit exhaustion classification

Layer / File(s) Summary
Signal recognition and validation
open-sse/services/accountFallback/creditExhaustionSignals.ts, tests/unit/credit-balance-exhausted-signal.test.ts, stryker.conf.json, changelog.d/fixes/18770-credit-balance-exhausted.md
The shared signal list adds credit_balance_exhausted. Unit tests cover matching and non-matching responses, and the Stryker TAP list includes the tests. The changelog describes the response classification.

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix

Merge Risk: Minimal · up to 29b9a

Accounts that return a 429 with credit_balance_exhausted are now treated as out of credits rather than retried after a short backoff. They recover automatically through the existing periodic reprobe. No concrete merge-blocking risk remains.

Pre-merge checks: Passed 6 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Description check Warning The description clearly explains the change, rationale, tests, and mutation-test configuration fix, but it does not follow the required template and omits the Related Issues, Target Branch, Validation… Update the description to use the repository template. Add the Related Issues and Target Branch sections, complete the Validation checklist, document coverage for the open-sse change, and add Reviewer Notes. List the changed test files unde…
Passed Passed checks: 6 passed
Check name Status Explanation
Title check Passed The title follows the required Conventional Commits format and accurately describes the primary change.
Docstring Coverage Passed No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Tests For Production Code Passed The PR changes production code in open-sse/services/accountFallback/creditExhaustionSignals.ts and adds tests/unit/credit-balance-exhausted-signal.test.ts. The new tests directly exercise the upda…
No Ai Attribution Passed No AI attribution found. The three commits in the reviewed range contain no Co-Authored-By or Generated with footer. The only trailer is Signed-off-by: Minxi Hou <houminxi@gmail.com>. The suppli…
Full details: Docstring Coverage

Explanation

No eligible functions found in the changed files. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 0 functions across 2 files. (2 skipped: 2 unsupported.)

Full details: Tests For Production Code

Explanation

The PR changes production code in open-sse/services/accountFallback/creditExhaustionSignals.ts and adds tests/unit/credit-balance-exhausted-signal.test.ts. The new tests directly exercise the updated signal list, including the new code, case handling, negative rate-limit behavior, and existing signals.

Full details: No Ai Attribution

Explanation

No AI attribution found. The three commits in the reviewed range contain no Co-Authored-By or Generated with footer. The only trailer is Signed-off-by: Minxi Hou &lt;houminxi@gmail.com&gt;. The supplied PR body contains neither prohibited attribution form.

Full details: Description check

Explanation

The description clearly explains the change, rationale, tests, and mutation-test configuration fix, but it does not follow the required template and omits the Related Issues, Target Branch, Validation, Coverage Notes, and Reviewer Notes sections.

Resolution

Update the description to use the repository template. Add the Related Issues and Target Branch sections, complete the Validation checklist, document coverage for the open-sse change, and add Reviewer Notes. List the changed test files under Tests Added Or Updated.

Finishing Touches
Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Usage-based review receipt

  • Mode: Continue automatically
  • Reviewed files: 4
  • Waived: $1.00 (charged $0.00)
  • View usage details

Note

This review exceeded your plan’s limits and used usage-based reviews—free during trial, billed after paid activation unless disabled. Manage usage-based reviews.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between f000c11 and 29b9a4f.

Files selected for processing: 4
  • changelog.d/fixes/18770-credit-balance-exhausted.md
  • open-sse/services/accountFallback/creditExhaustionSignals.ts
  • stryker.conf.json
  • tests/unit/credit-balance-exhausted-signal.test.ts

Limit details: You’ve used all 10 included reviews currently available.

@diegosouzapw
diegosouzapw merged commit 41843d8 into cheaper-inference:release/v3.8.53 Nov 4, 2026
13 of 34 checks passed
@HouMinXi
HouMinXi deleted the fix/credit-balance-exhausted branch November 4, 2026 11:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants