Persistent HTTP 429 on auto-mode classifier (xml_s1), account-side config

Resolved 💬 15 comments Opened May 19, 2026 by aguynamedryan Closed Jun 22, 2026
⚠️ UPDATE (June 2026) — ROOT CAUSE FOUND; the analysis below is superseded. This is not an account-side classifier-pool problem (the theory argued at length in this thread). The real cause is the client-side bug #64585 — disabling CLAUDE_CODE_ATTRIBUTION_HEADER (=0 / false) silently 429s the auto-mode safety classifier on capable models (opus/sonnet). Fix: unset that env var to return the header to its default, and the classifier works directly, no proxy. Confirmed by A/B on Claude Code 2.1.187. Closed in favor of #64585 — leaving this thread for history.

---

Update 2026-05-18: Still reproducing on Claude Code 2.1.144 (released 2026-05-19, ~12 hrs before filing). The 2.1.144 changelog contains no auto-mode-classifier model-selection or 429 fix. The 2.1.139 evidence below remains the cleanest on-record repro; nothing about the mechanism has changed across 2.1.139 → 2.1.144.

What's happening

On my Max account, every Claude Code auto-mode safety classifier call to claude-opus-4-7 is returning HTTP 429 rate_limit_error immediately (~1.5–2 s round-trip), at stage=xml_s1. The user-facing message that Claude Code surfaces translates this to "claude-opus-4-7 is temporarily unavailable, so auto mode cannot determine the safety of Bash right now", which is misleading — the underlying response is a 429 from /v1/messages on the classifier code path.

This is not a transient Messages-API rate limit:

  • Regular /v1/messages calls to claude-opus-4-7 from the same account, same authenticated session, succeed with HTTP 200 within minutes of the classifier 429s.
  • I have 46 distinct classifier-path 429s in today's CLAUDE_CODE_DEBUG_LOGS_DIR debug logs alone.
  • The same failure pattern persisted yesterday on a day with much lighter Opus usage.

It looks like an account-side misconfiguration: either a feature flag (tengu_auto_mode_config.model is unset in my GrowthBook profile, so the classifier falls through to the session model = Opus 4.7, which is then gated), or a per-account auto-mode-classifier rate-limit pool sized at ~0.

Same-minute proof this isn't a Messages-API pool exhaustion

All from today, 2026-05-12, same account:

| Time UTC | Request shape | Model | Result | ID |
|---|---|---|---|---|
| 15:32:10 | /v1/messages source=side_query classifier stage=xml_s1 | claude-opus-4-7 | HTTP 429 rate_limit_error, 1859ms | req_011Caxv75pXzufzvkvVBwP2d |
| 15:32:15 | /v1/messages source=side_query classifier stage=xml_s1 | claude-opus-4-7 | HTTP 429, 1904ms | req_011Caxv7SqqB7kP3QsyARBJB |
| 16:15:11 | /v1/messages source=sdk normal chat | claude-opus-4-7 | HTTP 200, returns "READY" | 219a8af6-b14d-4b42-98d4-1b255cdceddf (client) |
| 16:15:53 | /v1/messages source=sdk normal chat | claude-opus-4-7 | HTTP 200, returns "WORKING" | 2b35c463-8e94-4d60-b2e6-f083e644d3aa (client) |

If my Messages-API rate-limit pool were exhausted, the chat calls would 429 too — they don't. Different request shape, different gate, only one of them firing.

Binary-level isolation

The classifier-model selection lives in the ME7() function in the Claude Code binary (minified name, body invariant in v2.1.139):

function ME7(){let H=J$("tengu_auto_mode_config",{});if(H?.model)return H.model;return G4()}

When tengu_auto_mode_config.model is unset (my case), it falls through to G4() which resolves to the session model — claude-opus-4-7 for me.

I patched the binary in-place to hardcode the classifier model and re-ran the same probe (zoxide --version — not in my Bash allowlist, so it requires classifier escalation):

| Patched classifier model | Classifier outcome |
|---|---|
| claude-opus-4-7 (unpatched / default) | HTTP 429 rate_limit_error |
| claude-sonnet-4-6 | "temporarily unavailable" (consistent with the Max-plan classifier-model restriction in support's checklist response) |
| claude-haiku-4-5 | outcome=ok in 933–1460 ms |

So the classifier endpoint accepts and serves my account's requests fine. Only the claude-opus-4-7 classifier code path is gated on my account.

A coworker on a comparable Max + Opus 4.7 setup is not affected.

Auto-mode gate check passes (so it isn't a precondition failure)

From my own CLAUDE_CODE_DEBUG_LOGS_DIR:

[auto-mode] verifyAutoModeGateAccess: enabledState=opt-in disabledBySettings=false 
  model=claude-opus-4-7 modelSupported=true disableFastModeBreakerFires=false 
  carouselAvailable=true canEnterAuto=true

canEnterAuto=true. Claude Code is not reporting auto mode as unavailable; the client happily enters auto mode. The failure is downstream of the gate, in the classifier API call itself.

Preconditions I've cleared

  • Plan: Max (organizationType: "claude_max", tier default_claude_max_20x)
  • Model: claude-opus-4-7 (per Max-plan auto-mode requirement)
  • Provider: Anthropic API only (no Bedrock/Vertex/Foundry env vars)
  • Claude Code: originally captured on 2.1.139; still reproducing on 2.1.144 (both well past the 2.1.83 minimum)
  • skipDangerousModePermissionPrompt: true

Reproducer

mkdir -p /tmp/cc-check
CLAUDE_CODE_DEBUG_LOGS_DIR=/tmp/cc-check claude --print --debug api \
  --permission-mode auto --model claude-opus-4-7 \
  'Run the bash command `zoxide --version` exactly as-is and report what it printed.'
grep -E 'classifier_request|errorKind' /tmp/cc-check/*.txt

Expected: classifier_request_finished ... outcome=ok ...
Observed on my account: classifier_request_finished ... outcome=error ... errorKind=Error:429

Substitute any Bash command that isn't in your local allowlist.

What I've already ruled out

  • The [1m] suffix-propagation bug (#38537) — happens equally with and without suffix
  • Effort level — low/medium/high/xhigh/max all 429 identically
  • CLAUDE_CODE_EFFORT_LEVEL env var — unsetting it doesn't change behaviour
  • ANTHROPIC_DEFAULT_OPUS_MODEL alias remap — classifier sends explicit model ID, not alias
  • Patching cachedGrowthBookFeatures.tengu_auto_mode_config.model in ~/.claude.json — overwritten on next GrowthBook refresh
  • Local proxy via ANTHROPIC_BASE_URL — disables classifier entirely (dacEnabled=n/a, per cc-switch#1678)

What I'm asking for

In order of preference:

  1. An engineer to look at my account's GrowthBook tengu_auto_mode_config flag value and either set model to the correct value, or fix the classifier rate-limit pool sizing for my account.
  2. Documentation of the auto-mode-classifier rate-limit pool in https://docs.claude.com/en/api/rate-limits so users can self-diagnose. Today's docs don't mention it.
  3. Fix the misleading "temporarily unavailable" error message so it surfaces the actual underlying error (429 rate_limit_error).

Happy to share the full debug log bundle privately. I have already opened a support chat (conversations 215474274160046 and 215474274097794) but Fin's auto-template repeatedly terminates the chat with the "usage limit" stock response, blocking further reply. Hence this issue.

Related

  • #49837 — Auto Mode Classifier uses Opus 4.7 instead of Sonnet (this is the mechanism)
  • #49478 — claude-opus-4-7 temporarily unavailable blocks auto mode (this is the visible symptom)
  • #38537 — Suffix-propagation bug (related but separate; ruled out as my cause)

View original on GitHub ↗

15 Comments

github-actions[bot] · 1 month ago

Found 2 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/22876
  2. https://github.com/anthropics/claude-code/issues/40128

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

aguynamedryan · 1 month ago

Update — cross-referencing @akerckhofs's resolution on #49254 (https://github.com/anthropics/claude-code/issues/49254#issuecomment-4312917353), where DISABLE_TELEMETRY=1 blocked GrowthBook refresh and left their account with a tengu_auto_mode_config that had no model field, causing the same ME7() fallthrough to the session model.

That mechanism — GrowthBook delivering a tengu_auto_mode_config without a model field — is exactly what's happening here, but the cause is different. My telemetry is enabled, not disabled, and the GrowthBook cache is fresh.

Inspected ~/.claude.json just now:

  • Env: CLAUDE_CODE_ENABLE_TELEMETRY=1 (opposite of akerckhofs's setup)
  • cachedGrowthBookFeatures: 256 flags, last refresh 2026-05-21T09:53:27Z — current, not stale
  • cachedGrowthBookFeatures.tengu_auto_mode_config:

``json
{ "enabled": "disabled" }
``

No model field. ME7() does if (H?.model) return H.model; return G4() — so this object falls through to G4() → session model = claude-opus-4-7 → 429.

So same end state as akerckhofs (no model in delivered config), but the GrowthBook server is actively delivering this incomplete config to my account on every refresh, rather than the client serving a stale cache. That moves the bug from client (telemetry-cache-staleness) to server (GrowthBook flag delivery) for my case.

Bonus inconsistency worth flagging: the delivered config says "enabled": "disabled", but Claude Code's own auto-mode gate check reports canEnterAuto=true (see debug-log excerpt in the original report). Either the gate check ignores the enabled field, or it's evaluated at a different layer than ME7(). Either way it suggests tengu_auto_mode_config is being assembled/delivered inconsistently for my account.

Concrete ask, refined: please inspect what GrowthBook is configured to serve for tengu_auto_mode_config to account aguynamedryan / org 5b828240-385c-4a3c-860b-c95bffbda30e — both the rule that matches and the value it returns. The two observable symptoms (no model, enabled: "disabled") both point upstream of the client.

aguynamedryan · 1 month ago

Additional precedent — #44101 is direct evidence that the GrowthBook server can deliver a complete tengu_auto_mode_config to other accounts, mine just isn't getting one.

That issue's reporter (Team plan, Sonnet 4.6) inspected ~/.claude.json and found:

"tengu_auto_mode_config": {
  "enabled": "opt-in",
  "twoStageClassifier": true,
  "model": "claude-sonnet-4-6[1m]"
}

Three fields, including the model that ME7() checks for. My Max account (with telemetry enabled and GrowthBook cache fresh — 256 flags, refreshed today) is delivered:

"tengu_auto_mode_config": { "enabled": "disabled" }

One field, no model, no twoStageClassifier. Same flag, different payloads, different accounts.

So the GrowthBook flag itself is configurable enough to return a full classifier config — it just isn't returning one for my account. That moves this from "Claude Code client bug" to "GrowthBook rule for account aguynamedryan / org 5b828240-385c-4a3c-860b-c95bffbda30e is misconfigured."

Concrete diagnostic ask, narrowed: what's the GrowthBook rule that's matching my account for tengu_auto_mode_config, and why does it return {enabled: disabled} instead of the full {enabled, twoStageClassifier, model} payload that #44101's reporter receives? Symmetric inspection of both accounts' matched rules should make the misconfiguration obvious.

aguynamedryan · 1 month ago

Update — re-tested today (2026-05-21) on Claude Code 2.1.146 with a wire-level proxy intercepting outbound /v1/messages traffic, with the binary un-patched (ME7 returns the session model as it would by default).

Confirmed: Haiku is the only working classifier model for this account

Same patch-matrix results as 5/12, now via a different intercept point (proxy rewrites the model field in-flight rather than changing what the client sends):

| Classifier model (proxy-swapped) | Classifier outcome |
|---|---|
| claude-opus-4-7 (no swap, default) | HTTP 429 rate_limit_error |
| claude-sonnet-4-6 (proxy-swapped) | HTTP 429 rate_limit_error, durationMs=2618 |
| claude-haiku-4-5 (proxy-swapped) | outcome=ok durationMs=1198 |

The wire-level reproduction matters because it isolates the restriction from any binary-patch artifact: the proxy doesn't change Claude Code's behavior, only the model value the upstream API receives. So claude-sonnet-4-6 returning 429 here is upstream rejecting Sonnet as a classifier model for this account, not a client-side quirk. Haiku is the only model the classifier endpoint will serve for me.

Also, importantly, no dacEnabled=n/a in the debug log this time — the ANTHROPIC_BASE_URL-disables-classifier behavior I cited as ruled out in the original report was actually a side-effect of the binary patch, not of ANTHROPIC_BASE_URL alone. Worth correcting that ruled-out for the record: ANTHROPIC_BASE_URL + unpatched binary fires the classifier normally.

Binary string evidence of the circuit-breaker check

Found inside 2.1.146:

auto mode disabled: tengu_auto_mode_config.enabled === "disabled" (circuit breaker)

So tengu_auto_mode_config.enabled === "disabled" is a real circuit breaker — but on my account it's not firing. The gate-access debug line still says enabledState=enabled even though my cached tengu_auto_mode_config is literally {"enabled": "disabled"}. So the cached value and the value the circuit-breaker check reads against come from different sources. Another symptom of inconsistent state delivery for my account.

GrowthBook fetch endpoint

For anyone reading along: GrowthBook flag fetches go directly to https://cdn.growthbook.io, not through api.anthropic.com. ANTHROPIC_BASE_URL does not redirect them, so an HTTP proxy targeted at the Messages API can't intercept tengu_auto_mode_config delivery (would require DNS override + cert MITM). Mentioning it so the next person investigating this doesn't go down the same false trail.

Net engineering ask, sharpened

For my account / org 5b828240-385c-4a3c-860b-c95bffbda30e:

  1. Why does GrowthBook deliver tengu_auto_mode_config = {"enabled": "disabled"} to my account when other Max/Team accounts (#44101) receive the full {enabled, twoStageClassifier, model} payload?
  2. Why does the classifier endpoint accept claude-haiku-4-5 for my account but 429 on claude-opus-4-7 and claude-sonnet-4-6 (whereas Team accounts in #44101 are configured to use Sonnet)?
  3. Are those two questions one bug or two?
aguynamedryan · 1 month ago

Update — ~12 hours after the original report. A partial GrowthBook config change landed for my account, but the rate-limit side hasn't moved.

What changed

The cached tengu_auto_mode_config flipped from:

{ "enabled": "disabled" }

to:

{ "enabled": "enabled", "twoStageClassifier": true }

Still no model field, so ME7() / OJ7() in 2.1.146 still falls through to the session model (claude-opus-4-7 for me).

What didn't change

Just retested with everything else reset: unpatched binary, proxy disabled (unset ANTHROPIC_BASE_URL), fresh Claude Code 2.1.146 session, zoxide --version as the probe:

| Setup | Classifier outcome |
|---|---|
| Direct claude-opus-4-7 (no proxy, no patch) | HTTP 429 rate_limit_error, durationMs=1914 × 3 attempts |
| Wire proxy swapping → claude-sonnet-4-6 | HTTP 429 rate_limit_error, durationMs=2954 |
| Wire proxy swapping → claude-haiku-4-5 | outcome=ok durationMs=833 |

So Opus and Sonnet still 429 identically to the original report. The model-allow / rate-limit pool side of my account's classifier config is unchanged. Haiku-via-proxy remains the only working classifier model.

Why this is informative

Two GrowthBook-side knobs evidently move independently on this account:

  1. tengu_auto_mode_config.enabled — moved (disabledenabled)
  2. The model-allowlist / rate-limit pool that gates the classifier endpoint — unchanged

Someone has been touching my account's config since the original report (the enabled flip is not random), but only one of the two knobs the issue identified. Whatever's gating classifier access by model is a separate rule that wasn't touched.

Sharpened diagnostic ask

For account / org 5b828240-385c-4a3c-860b-c95bffbda30e:

  1. The tengu_auto_mode_config.enabled flip suggests someone is investigating — thank you. But there are still two unfixed things: (a) the model field is still absent from the delivered config, and (b) the classifier endpoint still 429s on every model except claude-haiku-4-5.
  2. Could whoever's looking at this also check the rule that controls tengu_auto_mode_config.model AND the per-model rate-limit pool sizing for the classifier endpoint? Those are the actually-load-bearing knobs.
  3. Operational note: I've cut over to a transparent local HTTP proxy that rewrites the model field on classifier requests to claude-haiku-4-5 on the wire. It's a stopgap; will retire it the moment the upstream config is fixed.
javan · 1 month ago

For my claude_max org the local config cache has tengu_auto_mode_config as { "enabled": "enabled", "twoStageClassifier": true }. Replaying a classifier request while changing only model gives claude-opus-4-7 → 429, claude-sonnet-4-6 → 429, and claude-haiku-4-5 → 200. Regular /v1/messages calls to the same model return 200 in the same minute. I can reproduce the classifier failure with the session model set to Opus 4.7 non-1M and Sonnet 4.6 as well.

In practice this means classifier errors do not stop for permission prompts. After a few denied tool calls / retries, Claude continues on without the denied context and often lands on poor solutions. Easy to miss unless you're actively observing.

seishonagon · 1 month ago

Corroborating on a Team plan (Claude Code 2.1.156) — and isolating the trigger to the auth/billing channel rather than the model.

Same root failure as this issue, reproduced today on a different plan tier and a newer build, with one extra isolation that I think narrows the cause.

Environment

  • Claude Code 2.1.156, macOS, first-party auth (claude.ai OAuth, no API key), subscriptionType: team.
  • Tiers (from ~/.claude.json oauthAccount): seatTier=team_tier_1, organizationRateLimitTier=default_raven, userRateLimitTier=default_claude_max_5x.
  • So this is not limited to Max / default_claude_max_20x — it also hits Team.

New isolation: same model — API key serves the classifier, the subscription 429s it

Where this issue patched the classifier model (and found Haiku ok), I instead held the model fixed at claude-opus-4-8 and changed only the auth/billing channel, using --bare (auth becomes strictly ANTHROPIC_API_KEY, bypassing the Team/OAuth subscription):

| Auth channel — same Mac, same binary, same model claude-opus-4-8, same gated action | classifier xml_s1 |
|---|---|
| Team subscription / OAuth | outcome=error errorKind=Error:429 (10/10, deterministic) |
| Console API key (--bare) | outcome=ok durationMs=1981, tool runs, 0×429 |

So the Opus classifier code path itself is fine — the endpoint serves claude-opus-4-8 side_query requests without issue on API-key billing. The single variable that flips it is the subscription/OAuth channel, which strongly supports your "per-account auto-mode-classifier rate-limit pool sized ~0" reading and locates it specifically on the subscription side. (The same subscription-vs-API-key split shows up for a different feature in #27074.)

Model × context matrix (session model = classifier model), on the Team subscription

| Session model | model string in classifier request | result |
|---|---|---|
| claude-opus-4-8 (1M) | claude-opus-4-8[1m] | 429 |
| claude-opus-4-8 (200k) | claude-opus-4-8 | 429 |
| claude-sonnet-4-6 (200k) | claude-sonnet-4-6 | 429 |
| claude-haiku-4-5 (200k) | (classifier not invoked — falls back to an approval prompt) | no 429 |

Confirms it is not tied to the [1m] suffix and not Opus-only on the subscription: claude-sonnet-4-6 (200k) 429s as well. Same verifyAutoModeGateAccess … canEnterAuto=true as you — the failure is downstream of the gate.

Probe-validity note (for anyone reproducing)

A Bash command covered by a deterministic allow rule (e.g. a read-only cat <file>) is fast-pathed (permissionDecisionMs≈3) and never invokes the classifier — like your zoxide (not-in-allowlist) trick, you need a gray-zone action (e.g. writing outside the project scope, touch ~/marker) to force the source=side_query call.

Sample 429 request_ids (first-party, for server-side lookup)

req_011CbWBZ8w9e3MD5R9ZpPXcB, req_011CbWBiwDyLwphMpxHU7Lsb (claude-opus-4-8), req_011CbWBnoegDgufRuKrieboo (claude-sonnet-4-6). Captured 2026-05-29. Happy to share the full --debug bundle privately.

BrownBear127 · 1 month ago

Reproducing on 2.1.158 + Opus 4.8 (native, macOS arm64). I can confirm the account-side / load-independent framing with on-disk forensics plus a binary trace of the model-selection path.

On-disk evidence — the CLI writes every classifier failure to /tmp/claude-$UID/auto-mode-classifier-errors/<session-id>.txt. A representative one:

=== ERROR ===
429 {"type":"error","error":{"type":"rate_limit_error","message":"Error"},"request_id":"req_011Cbb5LMGWo7YosS5Hj8cyF"}

=== CONTEXT COMPARISON ===
model: claude-opus-4-8[1m]
classifierTokensEst: ~10k

=== ACTION BEING CLASSIFIED ===
Bash <a routine read-only curl | jq one-liner>

=== SYSTEM PROMPT ===
You are a security monitor for autonomous AI coding agents...

I have 6 of these spanning 3 days — every one is a 429 rate_limit_error on the classifier request, with the session model logged as claude-opus-4-8[1m].

Why it lands on Opus, from the binary — the classifier model is selected as tengu_auto_mode_config.model ?? <session model>. When the account's tengu_auto_mode_config.model (server GrowthBook config) is unset, it falls back to the session model (Opus 4.8) instead of a cheap Sonnet. The classifier request then draws on a near-zero per-account classifier rate-limit pool and 429s on nearly every Bash. The gate is fail-closed, so the result is "auto mode cannot determine the safety of Bash" → all Bash blocked.

Load-independent (the key point): this is not token-quota exhaustion. Normal chat requests return 200 in the same minute the classifier returns 429, and it happens on light-usage days. It's a different pool / request shape, not your usage.

No clean local override: on 2.1.158 there's no settings.json / env knob that re-points the classifier model (confirmed by grepping the bundle — it's a server-side config). My env / settings.json / settings.local.json have nothing relevant set.

Not fixed in 2.1.159: I installed 2.1.159 (next tag) in isolation and diffed it against 2.1.158 — the auto-mode/classifier string literals and the classifierModel assignment sites are identical. The upcoming build doesn't touch this.

Ask: set tengu_auto_mode_config.model to a Sonnet tier for affected accounts (the intended path), or raise the per-account classifier rate-limit pool. Until then the only clean workaround is to leave auto mode — normal / acceptEdits modes issue no classifier call and never 429.

Related: #63873 #63819 #49837 #49535 #38618 (and the per-generation precursors #49254 / #49266 for Opus 4.7, both closed completed — yet the same failure returned with 4.8).

BrownBear127 · 1 month ago

Follow-up — cross-version evidence that this is account-side, not model- or profile-specific:

  • Same 429 rate_limit_error on Opus 4.6 (claude-opus-4-6[1m]), not just 4.8. The classifier falls back to whatever Opus session model is active, and every Opus tier draws the same near-zero per-account pool. (4.6 request id req_011CbbD5rGJCtneGTjsEGMCw.)
  • The limit is per-account (per OS user), not per-profile or per-model. I run two separate Claude Code profiles (different CLAUDE_CONFIG_DIR, same account). Their classifier error logs land in the same /tmp/claude-$UID/auto-mode-classifier-errors/ directory, and both 429 — switching profile or Opus version makes no difference.
  • Even read-only commands are blocked. The classified action in the 4.6 case was a plain read-only ls; auto mode routes every Bash through the classifier, so reads fail too during the outage.
  • Same failure as #49469 (Opus 4.6, closed completed) — i.e. it has recurred across 4.6 / 4.7 / 4.8 rather than being fixed.

Net: neither switching CLAUDE_CONFIG_DIR nor changing the Opus version helps. The only client-side escapes are leaving auto mode, or using a Sonnet session model so the classifier falls back to Sonnet. A real fix needs the account-side tengu_auto_mode_config.model set to a Sonnet tier.

aguynamedryan · 1 month ago

Update — workaround maturing, but the account-config bug is still the root cause (please fix that). Still reproducing on 2.1.159 as of 2026-06-01.

Sharing where I landed, mostly so others hitting this have a recipe — and as a measure of the engineering tax this imposes while the account-side config stays broken.

Evolution — credit where due: this approach isn't mine. @grechman built it first in #49837 — a localhost proxy that fingerprints the classifier by its system prompt and rewrites the model field (github.com/grechman/auto-mode-fix-to-sonnet). I started by binary-patching the model-selection function (ME7/YtK) just to prove the restriction (opus/sonnet→429, haiku→200), then adopted grechman's proxy shape because it's maintainable: rewrite the classifier sub-call's modelclaude-haiku-4-5 on the wire, foreground untouched.

Realities beyond the original workaround:

  • The SDK couples header betas to body fields (effort-2025-11-24effort, context-management-2025-06-27context_management, …). Strip a header beta whose body field remains → 400 "Extra inputs are not permitted". A minimal curl probe returns 200 and hides this; only a real claude -p reproduces it. Safe shape is a blocklist of header-only betas (e.g. context-1m-2025-08-07), never an allowlist.
  • **Haiku is the only model the subscription classifier pool serves** — consistent with @seishonagon's --bare/API-key isolation upthread (same model 200s on API-key billing, 429s on subscription → pool-side, not model-side).
  • **Even a proxy doesn't fully close it — delivery is the hard part. Any claude process whose env lacks ANTHROPIC_BASE_URL (children of a pre-change tmux server, non-interactive shells) sends its classifier direct and 429s — and it's not a rare edge case: ~32 of my ~41 running sessions were escaping the proxy this way until I fixed delivery. @BrownBear127's note that Claude Code logs each failure to /tmp/claude-$UID/auto-mode-classifier-errors/<session>.txt is a great canary (one file per failure, fingerprintable by mode); @javan's point that these 429s don't pause for a permission prompt — they silently degrade output — is why it's worth monitoring. What actually closes it: deliver ANTHROPIC_BASE_URL via settings.json env**, not the shell. In the 2.1.159 binary, settings env is applied with Object.assign(process.env, settingsEnv), so it overrides the inherited shell environment and reaches every process regardless of launch path. (Corollary, if you build a direct-connection fallback: once it's in settings, env -u ANTHROPIC_BASE_URL no longer escapes — you have to remove the key from settings.json.)

A stopgap — I'll retire all of it the moment tengu_auto_mode_config.model is set (or the per-account classifier pool is sized > ~0) for affected accounts. The ask is unchanged: fix the account-side GrowthBook config; the proxy is just the cost of it staying broken.

Code (unsupported, my setup, read before running): https://gist.github.com/aguynamedryan/a7b6bcf6fd9f3a5bb79fcf446000e4df

aguynamedryan · 1 month ago

Update (2026-06-11, re-verified on 2.1.173) — a client-side companion to this just landed (#67542), and it sharpens the ask here.

@PropterMalone's #67542 is a clean binary-level analysis of the client half of this: the auto-mode classifier's model selection (Rr7 in the 2.1.170 bundle) has no availability check and no retry-on-sibling — it targets whatever tengu_auto_mode_config resolves to, and when that model is unavailable it fails closed behind a tengu_iron_gate_closed Statsig gate (default true). They also probe-confirmed what I'd only seen black-box: CLAUDE_CODE_AUTO_MODE_MODEL is registered in the env-var table but never consulted — dead.

That issue's repro is a capacity event (a model goes temporarily unavailable). This issue is the persistent, capacity-independent sibling — same symptom, but it needs a different fix: a server-side repair of my account's classifier pool, not a client-side fallback or model override (I explain why below).

It's also symptomatically adjacent to the broader capacity-outage cluster (#63873, #63819, #49535) — but distinct from it, not a duplicate: those are transient model unavailability; this account 429s the classifier pool for every model except Haiku with no outage at all (opus/sonnet serve normal /v1/messages 200 in the same minute). A capacity fallback resolves that cluster and would not reach this case — so please don't fold them together.

My case has no outage: the per-account classifier pool 429s every model except Haiku

Re-verified today on 2.1.173, classifier request forced onto a direct connection (proxy bypassed):

| classifier side_query model | result |
|---|---|
| claude-opus-4-8[1m] | 429 / "temporarily unavailable" (×4 retries) |
| claude-opus-4-7[1m], claude-sonnet-4-6[1m] | 429 (earlier runs in this thread) |
| claude-haiku-4-5 (proxy-rewritten on the wire) | 200, action proceeds |

The same opus/sonnet models serve normal /v1/messages traffic 200 in the same minute — so this is the classifier side_query pool specifically, not the models. @seishonagon isolated it to the subscription/billing channel upthread: same claude-opus-4-8, Team subscription → 429 (10/10), Console API key via --bare200 (0×429). The per-account classifier pool is sized ~0 on the subscription side.

Confirming #67542's #4 directly: with CLAUDE_CODE_AUTO_MODE_MODEL=claude-haiku-4-5 set, today's request still went out as claude-opus-4-8[1m]. The override is dead.

The fix is to repair the pool — not to hand me a knob that pins me to Haiku

I want to be explicit here, because it's easy to mistake my proxy for the desired end state. It isn't. The proxy (rewrites the classifier sub-request's modelclaude-haiku-4-5 on the wire; origin @grechman's #49837) forces the classifier onto Haiku only because Haiku is the one model my account's pool will serve. Haiku is the least-capable classifier model, and running safety classification on a weaker model than my session itself uses is a real degradation — I rely on it under duress, not by choice. It's a stopgap, not a solution.

So a model-override knob — #67542's fix #2, a live CLAUDE_CODE_AUTO_MODE_MODEL — would not adequately fix this case: for my account it would only let me pin the degraded Haiku, making the hobbling permanent and official. The actual fix is server-side: restore my account's classifier side_query pool so it serves the capable models (opus/sonnet) — the way it already does for my normal /v1/messages traffic and, presumably, for other accounts. Repairing that pool is what retires the proxy and lets me classify with a model I actually trust.

Side note, verified today on 2.1.173 — scoped allow rules do skip the classifier

#67542 notes auto mode strips Bash(*) (Ignoring dangerous permission … (bypasses classifier)) and concludes there's no path to run non-read-only Bash during an outage. That holds only for the blanket wildcard. Narrower rules aren't strippedBash(ln:*) and a server-scoped mcp__clancey__* both ran on a direct connection with no classifier request emitted. So allowlisting the specific tools you need is a real, more-surgical escape hatch than disableAutoMode.

The ask

For account / org 5b828240-385c-4a3c-860b-c95bffbda30e: repair the per-account classifier side_query rate-limit pool so it serves the capable models (opus/sonnet). It currently 429s all of them and serves only Haiku — even though those same models return 200 on my normal /v1/messages traffic in the same minute. That is the fix, and the only one that lets me run safety classification on the same caliber of model as my session instead of being nailed to the weakest one.

For the record, what does not resolve this: a classifier-model override (#67542's fix #2) would only let me pin Haiku — formalizing the degradation, not fixing it; and #67542's capacity-fallback (fix #1) never reaches this case, since there's no outage to fall back from. This is a server-side pool/config defect on my account, and it needs a server-side fix.

aguynamedryan · 29 days ago

Re-verified on 2.1.179 (2026-06-17) — the pool 429 outlived the fix.

A direct classifier request to claude-opus-4-8[1m] (proxy bypassed) still returns 429 rate_limit_errorreq_011Cc96wyx6mXBLvAUyA7QSp — i.e. the per-account pool, not a 529/overload (which is what a transient global Opus outage would be). So 2.1.176's "auto mode classifier now falls back to the best available Opus model" did not reach this case: falling back to the model my pool refuses is no fallback at all. Same 429 rate_limit_error, latest release — still no movement on the pool itself.

(Cross-ref: #69002 proposes a configurable classifier model. Worth having, but it wouldn't fix this — for my account it would only let me pin Haiku, the weakest classifier model. The pool is the defect, not model selection.)

JScones · 24 days ago

My 2c, ignore if it doesn't help. I was experiencing 429s exclusively on classifier requests after messing with oMLX and claude.
At some point in the process I configured the env setting CLAUDE_CODE_ATTRIBUTION_HEADER to 0.
Once I switched back to cloud models, chat messages were fine and classifier attempts received 429s.

Removing this sorted it for me and I can repro it with the following:

❯ mkdir -p /tmp/cc-check
  CLAUDE_CODE_ATTRIBUTION_HEADER=0 CLAUDE_CODE_DEBUG_LOGS_DIR=/tmp/cc-check claude --print --debug api \
    --permission-mode auto \
    'Run the bash command `git --version` exactly as-is and report what it printed.'
  grep -E 'classifier_request|errorKind' /tmp/cc-check/*.txt
The safety classifier for auto mode is currently unavailable (`claude-sonnet-4-6 is temporarily unavailable`), which is blocking the Bash tool from running. This is a transient infrastructure issue. Please try again in a moment, or you can approve the command manually if prompted.
2026-06-22T07:31:54.861Z [INFO] [Stall] classifier_request_started reqId=bf9eefa0-93b0-4f30-94ed-b5c586feb646 tool=Bash model=claude-sonnet-4-6 stage=xml_s1 promptTokensEst=[REDACTED]
2026-06-22T07:32:03.754Z [WARN] [Stall] classifier_request_finished reqId=bf9eefa0-93b0-4f30-94ed-b5c586feb646 tool=Bash stage=xml_s1 outcome=error durationMs=8893 errorKind=Error:429 {"type":"error","error":{"type":"rate_limit_error","message":"Error"},"reque
...
aguynamedryan · 24 days ago

Resolved on my end — and the account-side framing in this thread was a misdiagnosis. Mea culpa.

The cause is client-side: #64585CLAUDE_CODE_ATTRIBUTION_HEADER=0. I had it set (as a prompt-cache optimization), and disabling it is what 429s the auto-mode classifier. Full credit to @JScones, whose comment above put me onto it.

Confirmed by A/B today, on a direct connection (proxy bypassed), reading the nested session's own --debug classifier log:

| direct — only the header changes | header OFF | header ON |
|---|---|---|
| claude-opus-4-8 | 429 rate_limit_error | 200 |
| claude-sonnet-4-6 | 429 rate_limit_error | 200 |

Same model, same endpoint (api.anthropic.com), the only variable is CLAUDE_CODE_ATTRIBUTION_HEADER. Re-enabling it (just unset the var) makes opus and sonnet classify normally — no proxy, no model override, nothing account-side.

So my earlier "per-account classifier pool" analysis was wrong, and I apologize for steering toward a server-side fix. The actual bug is that disabling the attribution header silently breaks the auto-mode safety classifier — chat works, the classifier 429s, and nothing points at the env var as the cause. That's a real footgun worth fixing client-side (the classifier shouldn't 429 just because the attribution block is absent). For anyone else 429ing on the classifier: check whether you've set CLAUDE_CODE_ATTRIBUTION_HEADER=0, and unset it.

Retiring my wire-proxy workaround. Thanks again @JScones.

aguynamedryan · 24 days ago

Closing: root cause is the client-side attribution-header bug (#64585) — re-enabled the header on my end and the opus/sonnet classifier works direct, no proxy. Full A/B analysis in my comment above. Consolidating the signal on #64585.