Repository navigation
fix(anthropic): rotate past an account whose organization disabled subscription access - #7175
vadymhimself wants to merge 1 commit into
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info
📝 Walkthrough
Merge Risk: ⚪ Minimal · up to
|
|
@coderabbitai review |
✅ Action performedReview finished.
|
|
Cross-reference for #7153 (auto-pause repeated permanent account refusals): the two PRs merge cleanly, but #7153's |
|
Thanks — agreed. If #7153 lands first I'll rebase this PR and map |
|
@coderabbitai full review |
✅ Action performedFull review finished. |
|
|
For triage: this is one of a set of small, single-concern fixes from running dev on a busy Claude Code + Codex gateway (one Mac mini, 6-account Anthropic pool, combo/waterfall). All are drafts with the readiness checklist ticked; the fork-PR workflows (hygiene/label/resolve-pr) are waiting for approval to run. Each was proven red on dev and green on its branch; dev + all of them has been serving that gateway since 2026-10-15 21:30 KST+1 with zero doomed sends. Quota / cache: #7176 (caller 1h TTL on the translated lane — live: post-idle cache write 89,511 → 7,255), #7193 (pool rotation re-binds the reasoning-replay owner), #7177 (declared client refusal → its 4xx, not a retryable 502), #7178 (Claude ingress keeps max_tokens on non-canonical Responses gateways), #7175 (org-disabled 403 rotates), #7191 (generic-OAuth pool 429 cools the account, not the combo target). Happy to rebase, split or merge any of these into a carry, whatever is easiest. |
⏳ DRAFT
What to do
Review readiness checklist
0/4 boxes ticked. This pull request was already a draft. Its draft status will be preserved after every issue above is resolved. |
554877a to
3ffd538
Compare
…bscription access
Anthropic refuses an OAuth account whose organization disabled Claude
subscription access with HTTP 403 `oauth_org_not_allowed` ("Your organization
has disabled Claude subscription access for Claude Code. ..."). The account
refusal classifier did not recognise it, so the pool kept selecting the
denied account and every turn routed there failed while healthy accounts
were available.
Classify it as an account refusal, by the structured type or code first and
by its whole message under `permission_error`, so the existing 403 path
cools the account for ACCOUNT_REFUSAL_COOLDOWN_MS and rotates. Like the
sibling entitlement refusals it is not marked for reauthentication: the token
is valid and a fresh login cannot lift an organization policy.
Co-Authored-By: Claude Code <noreply@anthropic.com>
3ffd538 to
bc3bbee
Compare
|
Being carried into #7224 with your authorship preserved; this PR will be closed when the bundle lands. |
…evidence fixes (#7191, #7204, #7187, #7209, #7175, #7185, #7193, #7197, #7198) (#7224) Carried from #7191, #7204, #7187, #7209, #7175, #7185, #7193, #7197, #7198 (one commit per source PR, original author preserved). Security review follow-up: the Anthropic 402 combo cooldown now validates the sending credential's ownership before cooling an account. Remote validation (hosted GitHub Actions unreliable; local tests not run by maintainer rule): union candidate codex/prr-integ-8 = dev c03eafd + #7224 + #7223 + #7225 + #7217 + #6454 + #6594 plus a Gentle Shell import-cycle fix (integ-9 e1f289c: typecheck + full suite on mini (Windows) and lidge (Linux), compared with the same host's dev runs) and a test-only Windows path-escaping fix for the reasoning-retention routing test (integ-10 0d4cba7, tree a2b309a: that file re-run on both hosts). Co-authored-by: Vadym O <bolein95@gmail.com>
Summary
oauth_org_not_allowedand "Your organization has disabled Claude subscription access for Claude Code. Use an Anthropic API key instead, or ask your admin to enable access."isAccountRefusalinsrc/oauth/anthropic-account-refusal.tsdid not recognise that refusal. As a result the denied account was never cooled. It stayed eligible, and every turn routed to it failed with 403 even when healthy pool accounts were available. On combos, each such turn also cost a hop and a target cooldown.oauth_org_not_allowedvalue is matched first, as eithererror.typeorerror.code(it joins the existing allowed-code list). The whole message is also matched underpermission_error, anchored the same way as its sibling entitlement messages. A prefixed or quoted copy of the message stays terminal.ACCOUNT_REFUSAL_COOLDOWN_MScooldown (10 min, orRetry-After), clears affinity and rotates to the next eligible account. If no retry send remains, it still records the cooldown.needsReauthmark would show a misleadingneeds-reauthstate inocx account list, and re-login could not clear the underlying cause. The cost of this choice is at most one refused send per account every 10 minutes while the organization keeps access disabled.structure/providers/anthropic-account-pool.md("Account entitlement refusal recovery") is updated to describe the accepted set.src/oauth/, so it needs amaintainer-sponsoredlabel before merge (CONTRIBUTING, pull request contract).Verification
upstream/dev7640a94,bun test tests/adapters/anthropic/anthropic-quota-dispatch.test.tsgave 41 pass, 3 fail. The 3 failures were theorganization-disabled 403 rotates and cools the refused account (0..2)cases:permission_error+ message,oauth_org_not_allowedtype, andoauth_org_not_allowedcode.Request denied: <message>passes before and after the fix.bun test --isolate tests/adapters/anthropic tests/claude-integration/messages-native-oauth.test.ts tests/claude-integration/anthropic2-native-routing.test.ts(Bun 1.4.3): 1406 pass, 0 fail.bun run test:changed(Bun 1.4.3 viaOCX_TEST_RUNNER_BUN): 14974 pass, 35 skip, 1 fail across 614 files.tests/cli/cli-connect-readiness.test.ts, "a rejected preferred runtime falls back without rewriting the saved selection". It fails identically on a cleanupstream/devcheckout (98 pass, 1 fail for that file plusgithub-copilot-wire-defaults), so this change did not cause it.github-copilot-wire-defaults"grok-4.6 reaches /responses on responses inbound replay" (5 s) under load. That test passes in isolation.bun run typecheck: clean.bun run structure:check: passed.bun run privacy:scan: passed.bun run testwas not run separately;test:changedalready reached 614 files through the import graph ofsrc/oauth/anthropic-account-refusal.ts. CI covers the rest.554877af9, no changes pushed):bun test tests/adapters/anthropic/anthropic-quota-dispatch.test.ts44 pass / 0 fail;bun test --isolate tests/adapters/anthropic tests/claude-integration/messages-native-oauth.test.ts tests/claude-integration/anthropic2-native-routing.test.ts1406 pass / 0 fail;bun run typecheck,bun run structure:check,bun run privacy:scanclean. An independent review found no defects.git merge-treeagainst feat(accounts): auto-pause repeated permanent account refusals #7153 merges cleanly; feat(accounts): auto-pause repeated permanent account refusals #7153'sclassifyPermanentAccountRefusaldoes not yet recognize thisoauth_org_not_allowedrefusal, so that PR is the one to extend.Checklist
Review readiness checklist
This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:
Required local validation passed; commands, results, and any full-suite exception are documented.
I pushed my PR to a recent dev commit (at most 10 behind; a maintainer may still ask for the exact tip before merge).
I resolved all correct Codex and CodeRabbit findings.
My PR is ready for review.
🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
permission_error, matching organization-disabled subscription messages also qualify for account recovery, including messages with instructions to use an API key or ask an administrator to enable access.Documentation