Repository navigation
Usage → Limits merges two Codex subscriptions that share an email address #10835
Description
Activity
Triage
Confirmed. Usage → Limits drops one of two independent Codex subscriptions when they share an email.
Both instances are collected correctly (distinct plans, windows, reset credits, same
checkedAt). The loss is inpackages/shared/src/usageLimits.ts:accountKeyisdriver:normalizedEmail, andcollectLimitAccountsmerges on that key. TheLimitAccountcomment treats one email as one quota bucket. That is right for one subscription signed in twice (native + hub, or two environments). It is wrong for a personal Plus plan and a Business workspace on the same ChatGPT email — those are two quotas. EqualcheckedAtmakes the freshness>false, so iteration order decides which snapshot survives.collectLimitSourcesuses the same key and would hide a hub seat that shares the email.collectProviderUsageLimitson currentmainstill emits one row per native instance, so/usage-limitsshould still show both.This is the opposite of #10701 (double-count the same subscription). #10700 fixes #10701 by applying this email key to native
/usage-limitsrows and must not be treated as a fix here. Landing #10700 unchanged would extend this over-merge into the slash command.Web and mobile both render
collectLimitAccounts(UsageLimitsPooled). Pooling itself came from #10300;accountKeyfrom #9584. #9040 / #9884 / #7170 / #9676 are unrelated.Fix: keep same-email merge when the plan matches (
provider.auth.label/ hubplan— Codex already labels Plus vs Business viacodexPlanLabel). Split when the plan differs. Add a same-email Plus + Business regression next to the existing “two instances, one environment” test. Coordinate with #10700 so both collectors share that identity. Residual: two Business workspaces with the same email and the same plan string would still collapse.No in-app workaround; the second quota is only visible outside T3 Code.
- addedbugSomething is broken or behaving incorrectly.Something is broken or behaving incorrectly.acceptedfeature request acceptedfeature request acceptedvia-triageFiled through npx t3 triageFiled through npx t3 triage
on Sep 8, 2026 Same bug reproduces with Claude, and the proposed fix (split when the plan label differs) only partly covers it.
Setup
- One Anthropic login (one email) that belongs to two Claude orgs: a personal org on a Max plan, and a company Team org.
- Two Claude provider instances in T3 Code, one with the default home and one with
CLAUDE_CONFIG_DIRpointing at a second home (~/.claude-team), each signed in to a different org. - Both instances authenticate and both report their own limits when probed directly. Anthropic's
oauth/usageendpoint returns different session / weekly / model-scoped windows for each token, with different reset times.
Result
Usage → Limits shows a single Claude card.
accountKeyisclaudeAgent:<email>for both instances, socollectLimitAccountsmerges them. Because the merge keeps the freshercheckedAt, the surviving numbers silently flip between the two orgs depending on which instance was probed last. In my case the card showed the personal org at 36% weekly used while the Team org was at 2%, with nothing indicating which org the card represented.Why plan label is not enough for Claude
Two orgs on the same email can legitimately share a plan string (two Team orgs, or Team plus a Max seat both labelled by tier). For Claude the reliable identity is the org, and it is already on disk:
.claude.jsonin each config dir carriesoauthAccount.organizationUuidandorganizationName, and they differ between the two instances whileaccountUuidandemailAddressare identical. Keying the Claude account ondriver + organizationUuid(falling back to email when it is absent) would split the two quotas correctly and keep the "same subscription signed in twice" merge working, since a duplicate login to the same org has the same org UUID.For Codex the equivalent is
chatgpt_account_idin theauth.jsontoken claims, which differs per workspace even when the email and plan match. That would also close the residual "two Business workspaces, same plan string" case noted in triage.A small UI improvement regardless of the key: when a card is backed by more than one instance, show the org / workspace name so users can tell which quota they are looking at.
T3 code shows three of my four accounts from cli proxy.
Same issue, two share an email address.
Reacted by Paul CookConfirmed the Claude organization variant on Linux desktop with T3 Code Nightly
0.0.46-nightly.20261003.2632, build commitf391794a35c604d57e166a3ab48d56fc6e4e469a, and Claude Code2.1.288. Adding this here because #13674 was closed as a duplicate of this issue.Two configured Claude instances are enabled, installed, ready, and authenticated. They have the same email but different
oauthAccount.organizationUuidvalues in their separate Claude config directories. One is a Team subscription and the other is Max. Usage → Limits hides the Max instance under the Team instance's display name.The current T3 provider caches contain distinct quota data. No credentials or personal identifiers are included below.
Instance Auth label Usage checked at, UTC Weekly used Weekly reset, UTC Enterprise Claude Team Subscription 2026-10-03 17:25:46.469 62% 2026-10-07 17:00:00.133 Work Claude Max Subscription 2026-10-03 17:25:48.107 41% 2026-10-06 11:59:59.807 Work also has a separate
seven_day_fablewindow at 3% used. Both caches report one reset credit.The installed frontend matches upstream's accountKey at this build commit: when an email is present, the key is only
driver:normalizedEmail. The collector retains the first instance's display name and the freshest quota snapshot, so separate organizations can appear as one named account with the other organization's usage numbers.The existing same-email, separate-organization reproduction still applies on this nightly. The account identity needs to distinguish organizations while continuing to merge duplicate logins to the same organization.
- added 2 commits that reference this issue
on Oct 5, 2026 Written and posted by an AI agent (GPT-6-Astra through the Codex harness in T3 Code) on behalf of @alex73630, at their request. The observations below are the user's.
Friendly bump — I'm seeing the same issue with Orchestrator V2. I have two ChatGPT subscriptions on the same email: one on my Personal workspace and one on my Team workspace. Usage → Limits only shows one, and which subscription it represents looks arbitrary to me.
This makes the Limits tab mostly unusable for my setup: I can't reliably check the remaining quota for each subscription. I'd like both workspaces to appear separately, with clear labels and their own usage limits and reset times.
Could #10845 and #14750 get a review toward merging, once any remaining issues are addressed? #10845 addresses the Codex case I'm experiencing, while #14750 covers the related Claude organization case reported here. I haven't tested either patch locally; this is confirmation of the current problem and a request to help move the fixes forward.
Thanks for the work on these fixes — having reliable limits for each subscription would make this page much more useful!
What happened
I have two ChatGPT subscriptions, a Business one and a personal Plus one. I set them up as
two Codex provider instances using the shared
CODEX_HOMEplus shadow home layout from theCodex provider docs. Both instances work and both report as authenticated, each showing its
own plan in provider settings.
Under Usage → Limits, only one of the two Codex accounts appears. I expected to see both,
one segment per account, the way the docs describe pooling.
Diagnosis
T3 Code collects usage limits from both instances correctly. The provider status caches for
both instances were refreshed in the same batch and each holds distinct, live data:
The loss happens in the display layer, in
packages/shared/src/usageLimits.ts.accountKey(line 148) identifies a subscription account by provider driver plus lowercasedemail address:
collectLimitAccounts(line 187) merges on that key at line 257. Both of my Codex loginsreport the same email address, so both instances collapse into one
LimitAccountand onlyone set of windows survives.
The assumption is stated in the
LimitAccountdoc comment at line 153:That holds for one subscription signed in twice. It does not hold here. A single ChatGPT
email can carry a personal Plus subscription and separately belong to a Business workspace.
Those are two subscriptions with two independent quotas, so this merge understates what is
available rather than avoiding a double count.
Which of the two survives is arbitrary. The merge keeps the fresher snapshot, compared with
a strict
>at line 220. Both instances are probed in the same pass and carry an identicalcheckedAt, so the comparison is false and whichever instance is iterated first wins.The plan string that distinguishes them is already carried on the account as
provider.auth.label,so the two subscriptions are separable with data the collector already has.
Two other call sites use the same key and may want the same treatment.
collectLimitSourcesuses it at lines 105 and 133.
collectProviderUsageLimitsat line 639 pushes one entry pernative instance and uses the key only to suppress hub duplicates, so it looks unaffected, but
I did not verify its rendered output.
Steps to reproduce
a ChatGPT Business workspace. These are two subscriptions with separate quotas.
codex login.CODEX_HOME pathat thedefault and set its
Shadow home pathto~/.codex-t3/personal. Give the two instancesdifferent display names.
Expected: both Codex accounts appear, each contributing its own windows and its own segment.
Actual: one Codex account appears. The other subscription's quota is not shown anywhere on
the page.
Version
0.0.41-nightly.20260908.1414
Environment
macOS 26.6.2 (arm64), Node v24.14.0, codex-cli 0.153.4
Evidence
Related issues
None found. I searched the tracker for usage limit account merging, duplicate accounts,
pooled limits, and same-email variations, and nothing matches. #9040, #9884, #7170 and
#9676 all touch DPoP or relay authentication and are unrelated.
Fix applied or workaround
None. Nothing was changed on the machine. There is no setting that disables the
deduplication, so there is no in-app workaround. Reading the second subscription requires
going outside T3 Code.
Filed by
Claude Code (claude-opus-5, 1M context) via
t3 triage