router-for-me / router-for-me/CLIProxyAPI

[Bug] Stale Codex resets_at blocks paid account failover after the account is already usable

Open
#5,404 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

pending
Dominant language
Go
Stars
52.5k
Forks
7.9k
Avg merge
1d 3h
Merged PRs (30d)
60

Description

Is it a request payload issue?

  • Yes
  • No, it is a persisted Codex quota/cooldown issue.

Describe the bug

A paid Codex OAuth account can remain excluded from routing until an old usage_limit_reached.resets_at deadline even after the same account is accepted by upstream again.

In a two-account pool, account B was kept in a persisted model cooldown. When account A later exhausted its quota, failover failed because both credentials were considered locally unavailable. Restarting CLIProxyAPI did not help because save-cooldown-status: true restored the cooldown. Toggling account B disabled -> active cleared the local state, and the next request through account B immediately returned HTTP 200, about 98 hours before the cached deadline.

No upstream quota reset, OAuth re-login, token refresh, or credential replacement was performed during recovery; the logs show only Management API status PATCHes.

Timeline (local time, UTC+4)

2026-08-31 01:05:14 account B upstream 429:
  type=usage_limit_reached plan_type=pro
  resets_at=1788643357 (2026-09-06 01:22:37 +04)
  resets_in_seconds=519443
  -> local cooldown=144h17m22s

2026-09-01 22:32:07 account A upstream 429:
  type=usage_limit_reached plan_type=pro
  resets_at=1788747928 (2026-09-07 06:25:28 +04)
  resets_in_seconds=460401

2026-09-01 22:32:19 selector:
  2 of 2 candidates are in cooldown
  account A remaining=127h53m08s
  account B remaining=98h50m17s

2026-09-01 23:36:37 CLIProxyAPI 7.2.147 restarted
2026-09-01 23:37:50 both cooldowns were restored; account B remaining=97h44m46s

2026-09-01 23:47:10 PATCH /v0/management/auth-files/status (account B disabled)
2026-09-01 23:47:11 PATCH /v0/management/auth-files/status (account B active)
2026-09-01 23:47:17 selector chose account B
2026-09-01 23:47:19 POST /v1/responses -> HTTP 200

This confirms that the cached paid-plan deadline no longer represented actual upstream availability, while CLIProxyAPI had no request path that could observe the recovery.

Expected behavior

A paid Codex credential that becomes usable before an old advertised deadline should eventually be reconsidered without requiring an operator to clear its cooldown manually. This should be bounded/backed off rather than a tight polling loop.

Actual behavior

parseCodexRetryAfter uses the full future resets_at, the model state is persisted to .cds, restored after restart, and filtered before any upstream request. request-retry cannot help because no eligible credential reaches the executor.

CLI Type

Codex OAuth, two ChatGPT Pro accounts.

Model Name

gpt-5.6-sol

LLM Client

Codex app / codex-tui 0.151.0, Responses API.

Request Information

POST /v1/responses. This is not payload-dependent; consecutive requests were rejected locally in 8-16 ms while both auths were in cooldown. The first request after clearing only the local auth state succeeded through upstream in 1.895 s.

Environment

  • CLIProxyAPI 7.2.147, commit 17a65ee5
  • macOS 26.6.2, arm64
  • routing.strategy: fill-first
  • save-cooldown-status: true
  • disable-cooling: false
  • request-retry: 3
  • WebSocket-capable Codex OAuth auths

Related

  • #5277 describes stale cooldown after an explicit upstream quota reset; it was closed in favor of manual POST /v0/management/reset-quota.
  • #4248 already proposes a bounded paid-plan recheck. This report provides a current v7.2.147 real-world reproduction where no upstream reset action was performed and stale cooldown prevented two-account failover.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with parseCodexRetryAfter, the persisted cooldown model state, and the selector path that filters credentials before the executor request. Reproduce the two-account case with save-cooldown-status enabled, then verify that bounded paid-plan rechecks reconsider an account before resets_at without tight polling or manual status changes.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
api, backend
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.