Skip to content

[Bug] 2.77.0: "Use credits" never applies after weekly limit — credits.allowed copied from rate_limit.allowed #6571

Closed

Description

@sungyongcho

Client or integration

Codex App

Area

Authentication and account pool

Summary

Regression in 2.77.0 (introduced by 6ef255f "fix(codex): require consent for spendable-credit headroom (carry #6466)").

After the main Codex account hits its weekly included-usage limit, enabling "Use credits" for the main account in Codex Auth has no effect. Every request is rejected locally with HTTP 429 CodexMainAccountCreditsOffError even though upstream reports spendable credits and the model as available.

Root cause: credits.allowed is populated from data.rate_limit.allowed, and hasSpendableCodexCredits() returns false whenever credits.allowed === false.

// src/codex/quota.ts:929 (v2.77.0, credits snapshot)
...typeof data.rate_limit?.allowed === "boolean" ? { allowed: data.rate_limit.allowed } : {},

// src/codex/quota-types.ts:45 (v2.77.0, hasSpendableCodexCredits)
if (age < 0 || age > CODEX_CREDITS_FRESHNESS_MS || credits.allowed === false || ...) return false;

rate_limit.allowed describes the included plan window only. It is always false once limit_reached: true, which is exactly the situation where credits are supposed to take over. So hasSpendableCodexCredits() can never return true at the moment it matters, mainCreditsHoldResetAt() always returns a reset time, and assertMainAccountPolicy() throws before the request reaches upstream (~10 ms 429s).

Expected: with creditCodexAccountIds containing __main__, and upstream reporting credits.has_credits: true, balance > 0, overage_limit_reached: false, spend_control.reached: false and model_usage[model].available: true, requests should be forwarded and billed to credits (as they were on 2.76.0).

Suggested fix: do not derive credits.allowed from rate_limit.allowed. If a refusal signal is needed, use model_usage[<model>].available / spend_control.reached / credits.overage_limit_reached instead.

Reproduction

  1. Have the main ChatGPT (Pro) account at 100% of its weekly Codex limit, with a positive ChatGPT credits balance.
  2. Codex Auth → main account → enable "Use credits" (creditCodexAccountIds now contains __main__).
  3. Send any request from Codex App through the proxy (model gpt-6-astra).
  4. Observe: 429 rate_limit_exceeded, failureStage: "headers-only", failureCause: "rate-limit", with the message below. Toggling the setting or waiting for a quota refresh doesn't help.

Timeline from dpkg.log / usage.jsonl on my machine:

  • 12:06:03 upgrade open-codex 2.76.0 → 2.77.0
  • before that: main-account openai requests returned 200
  • 12:06:18 first CodexMainAccountCreditsOffError, and every main-account request since then is a 429

Version

2.77.0 (deb open-codex). Last known good: 2.76.0

Operating system

Ubuntu 26.04.1 LTS (x86_64)

Provider and model

openai (native Codex / ChatGPT main account), gpt-6-astra

Logs or error output

Proxy usage record (trimmed):

{
  "provider": "openai",
  "model": "gpt-6-astra",
  "admissionKind": "loopback",
  "status": 429,
  "durationMs": 10,
  "errorCode": "rate_limit_exceeded",
  "upstreamError": "Codex main account reached its usage limit, and spending ChatGPT credits is off or no fresh spendable balance is available. Choose another account, wait for the limit to reset, or allow the main account under \"Use credits\" in Codex Auth.",
  "routeDecision": { "routeKind": "native", "selected": { "provider": "openai", "model": "gpt-6-astra", "reason": "native-family" } },
  "failureStage": "headers-only",
  "failureCause": "rate-limit"
}

Upstream GET /backend-api/wham/usage at the same time (identifiers removed, balance rounded):

{
  "plan_type": "pro",
  "rate_limit": { "allowed": false, "limit_reached": true,
    "primary_window": { "used_percent": 100, "limit_window_seconds": 604800 } },
  "model_usage": { "gpt-6-astra": { "available": true, "available_at": null, "credits_would_enable": false } },
  "credits": { "has_credits": true, "unlimited": false, "overage_limit_reached": false, "balance": "~52000" },
  "spend_control": { "reached": false, "individual_limit": null },
  "rate_limit_reached_type": { "type": "rate_limit_reached", "details": "default" }
}

Resulting cached main quota in codex-quota-cache.json:

"credits": { "hasCredits": true, "unlimited": false, "overageLimitReached": false, "allowed": false, "balance": 52015.75 },
"weeklyPercent": 100

Redacted configuration

{
  "codexMainAccountHardLock": false,
  "creditCodexAccountIds": ["__main__", "<account-2>", "<account-3>"]
}

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

  1. added
    bugSomething isn't working
    account-poolOAuth, credentials, Codex pool, quota, failover, plans
    on Oct 4, 2026
  2. Ingwannu commented on Oct 4, 2026

    @Ingwannu
    Owner

    Confirmed against trusted dev 33185c2ccf7085f94357d9e56512803949b22cc5; the included-plan flag was incorrectly copied into the credit-specific veto. I opened draft #6572 at e7ee61d1cd65b52c07cc1dba34c506a6444e9254 with credit-specific spending-control parsing, opt-in/balance/freshness/overage/hard-lock preservation, and parser/main-admission regressions. The old implementation fails six new/corrected parser cases; the patched parser and main suites pass 60 tests, 0 failures, 141 assertions. Structure and file-size checks pass. Typecheck timed out under CPU75%/RAM1536M and is explicitly incomplete; broader CI and independent credit-boundary review remain pending. No real account, cache, provider call or credit spending was changed. This is a proposed fix, not a merged or released fix; the issue stays open.

  3. added a commit that references this issue on Oct 4, 2026
    2dd3f82
  4. Ingwannu commented on Oct 4, 2026

    @Ingwannu
    Owner

    Fixed on dev by #6572, merged by lidge-jun at 2dd3f82. Closing the reported 2.77.0 regression: included-window rate_limit.allowed no longer supplies credits.allowed; credit-specific spend_control, opt-in consent, freshness/balance and hard-lock checks remain. The final follow-up also vetoes malformed present controls and retracts cached permission on control-only refusals.

    Exact-head CI37209972954 passed for e9bcbe9. The parser/main-admission regressions and independent-review receipt are documented in #6572; earlier locally executed counts remain head-bound, not a new real-account run. This is a dev fix, not a claim that a release is published or the reporter's installed account has been exercised. Thank you @sungyongcho; attribution is retained in the landed commit.

  5. added a commit that references this issue on Oct 7, 2026
    5b3f78a
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, plansbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions