Repository navigation
Usage limit incorrectly shared across different accounts #23706
Description
What version of the Codex App are you using (From “About Codex” dialog)?
26.513.31313 (2867)
What subscription do you have?
plus & team
What platform is your computer?
No response
What issue are you seeing?
Environment
- Platform: Codex / ChatGPT
- Account A: ChatGPT Plus
- Account B: ChatGPT Team
- OS: macOS
- Browser: Chrome
- Region: Japan
Description
After reaching the 5-hour usage limit on Account A (Plus subscription), I switched to Account B (Team subscription). However, Account B immediately showed the same “5-hour limit reached” message, even though Account B had not been used at all during that period.
This makes it appear that the usage quota is being shared or cached across accounts unexpectedly.
Steps to Reproduce
- Log into Account A with a Plus subscription
- Use Codex until the 5-hour usage limit is reached
- Log out of Account A
- Log into Account B with a Team subscription
- Open Codex
- Observe that Account B also shows the “usage limit reached” message immediately
Expected Behavior
Account B should have its own independent usage quota and should not inherit the usage limit status from another account.
Actual Behavior
Account B incorrectly shows that the 5-hour limit has already been reached, despite having no usage during that time window.
Additional Context
- The issue may be related to:
- browser session caching
- device-level rate limiting
- IP-based quota enforcement
- shared authentication/session state
- Tried:
- logging out/in
- refreshing browser
- switching accounts
- Issue still persists
Impact
This prevents access to Codex on a separate paid Team account and blocks normal usage.
What steps can reproduce the bug?
Feedback ID: no-active-thread-019e45f5-b69e-7cc2-a5b2-2815a8fcd390
What is the expected behavior?
No response
Additional information
No response
Activity
jshaofa-ui commentedon May 20, 2026
Solution: Usage Limit Incorrectly Shared Across Different Accounts
Issue: openai/codex #23706
Labels: bug, codex-web, auth, rate-limits, app
Created: 2026-05-20
Estimated Value: $2,000–$3,000
Executive Summary
When a user is authenticated with multiple ChatGPT accounts simultaneously (e.g., a personal ChatGPT Plus account and a Team workspace account), the Codex app-server incorrectly shares rate limit state across accounts. The root cause is that the
AccountRequestProcessormaintains a singleAuthManagerinstance that caches auth state globally, and thefetch_account_rate_limits()method does not properly scope rate limit queries to the requesting account's context. This causes users on Team accounts to see depleted rate limits from their personal Plus account, and vice versa.The fix requires:
account_idChatGPT-Account-IDheader is always set when fetching rate limitsRoot Cause Analysis
Architecture Overview
The Codex app-server (
codex-rs/app-server) manages authentication through a singleAuthManagerinstance shared across all WebSocket connections:Bug Location
File:
codex-rs/app-server/src/request_processors/account_processor.rsMethod:
fetch_account_rate_limits()(lines ~878–920)Detailed Analysis
1. Global Auth Cache Without Account Isolation
The
AuthManager(incodex-rs/login/src/auth/manager.rs) maintains a singleCachedAuthin anRwLock:When
auth()orauth_cached()is called, it returns the globally cached auth. In a multi-account scenario where a user might be connected with different accounts in different browser tabs/connections, this global cache means:auth_manager.auth()returns Plus authauth_manager.auth()returns Plus auth (stale!)2. Missing Account Context in Rate Limit Queries
The
BackendClient::from_auth()method creates an auth provider fromCodexAuth, which includes theaccount_id. However, when the auth comes from the global cache (which may be stale for a specific connection), theChatGPT-Account-IDheader in rate limit requests points to the wrong account.From
codex-rs/model-provider/src/bearer_auth_provider.rs:The
account_idis derived fromCodexAuth::get_account_id(), which reads from the cached token data. If the cache is stale, the wrongaccount_idis sent.3. No Per-Connection Account Context
The
AccountRequestProcessordoes not track which account a specific WebSocket connection is authenticated as. Thefetch_account_rate_limits()method has noaccount_idparameter — it blindly uses the global auth:Compare with
get_account(params: GetAccountParams)which at least accepts parameters, though it still uses the global auth.4. Rate Limit State Not Account-Scoped
Even if the correct account is used for the API call, the rate limit snapshots are not cached per-account. The
RateLimitSnapshotstruct (fromcodex-rs/codex-api/src/rate_limits.rs) containslimit_id,plan_type,primary,secondary, andcredits— but noaccount_idfield. This means:Impact
Proposed Fix
Fix 1: Add Account-Scoped Rate Limit Caching
File:
codex-rs/app-server/src/request_processors/account_processor.rsAdd an account-scoped rate limit cache to
AccountRequestProcessor:Fix 2: Accept Account ID in Rate Limit Queries
File:
codex-rs/app-server-protocol/src/protocol/v2.rs(or equivalent)Update the
get_account_rate_limitsmethod to accept an optionalaccount_idparameter:Fix 3: Scope Rate Limit Fetching to Specific Account
File:
codex-rs/app-server/src/request_processors/account_processor.rsRewrite
fetch_account_rate_limitsto properly scope to the target account:Fix 4: Ensure ChatGPT-Account-ID Header in All Rate Limit Calls
File:
codex-rs/backend-client/src/client.rsVerify that
BackendClient::from_auth()correctly propagates the account ID:Fix 5: Invalidate Rate Limit Cache on Account Switch
File:
codex-rs/app-server/src/request_processors/account_processor.rsClear the rate limit cache for the old account when switching:
Test Plan
Unit Tests
Test: Rate limits are scoped to account
fetch_account_rate_limits(Some("account_plus"))returns Plus limitsfetch_account_rate_limits(Some("account_team"))returns Team limitsTest: Cache invalidation on account switch
Test: Stale cache refresh
Test: Account mismatch error
Integration Tests
Test: Multi-connection rate limit isolation
Test: Rate limit header propagation
/wham/usageor/api/codex/usageChatGPT-Account-IDheader matches the authenticated accountE2E Tests
Regression Tests
account_idparameterImpact Assessment
Risk Level: Medium
account_idparameter is backward compatibleFiles Modified
codex-rs/app-server/src/request_processors/account_processor.rscodex-rs/backend-client/src/client.rsfrom_auth()codex-rs/app-server-protocol/src/protocol/account_idto rate limit params (if needed)Dependencies
tokio::sync::RwLockandHashMapMigration Path
account_idparameteraccount_id) remains unchanged for single-account usersRollback Plan
Additional Considerations
Why This Bug Occurs
The
AuthManagerwas designed as a singleton because the CLI tool typically runs with a single account. However, the app-server (used by the web/desktop app) serves multiple connections that may represent different accounts. The rate limiting code path inherited the CLI's single-account assumptions without accounting for multi-connection scenarios.Alternative Approaches Considered
Per-connection AuthManager — Would require significant refactoring of the app-server architecture. Higher risk, more invasive.
Server-side account scoping — Would require OpenAI backend changes. Not feasible for a client-side fix.
This approach (account-scoped cache) — Minimal changes, backward compatible, addresses the root cause directly.
Monitoring Recommendations
Estimated Effort
Document generated: 2026-05-21
Analysis based on openai/codex main branch as of 2026-05-20
AdrianNO1 commentedon Jun 11, 2026
I have this issue too. #16894 is a potential duplicate.