[BUG] Auto mode classifier builds 5 cache_control blocks → API 400, surfaced as "<model> is temporarily unavailable" (regression 2.1.220 → 2.1.222)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report (please file separate reports for different bugs)
- [x] I am using the latest version of Claude Code
What's Wrong?
Since 2.1.222, auto mode denies every Bash/Edit action when the working directory has a
CLAUDE.md. The visible message says a model is temporarily unavailable, which sends you
looking at quota and provider status. The debug log shows something else entirely: the auto
mode classifier request carries 5 blocks with cache_control — one more than the API allows —
so it is rejected with 400 invalid_request_error. The CLI then retries with a fallback model,
which builds the same oversized request and 400s again, and auto mode fails closed.
So the action is not denied because a model is unavailable; it is denied because the request
the CLI itself constructed is invalid. Both models were reachable the whole time.
This is a regression. Same directory, same settings, same command: 2.1.220 works, 2.1.222
does not.
What Should Happen?
Two things:
- The classifier request should stay within the 4-block cache_control limit, so auto mode
keeps working in a directory that has CLAUDE.md / project memory context.
- A 400 invalid_request_error should not be surfaced as "<model> is temporarily
unavailable". That wording points at capacity, quota and provider health, none of which
were involved — it cost me most of a day. Reporting the real error kind (or even just
"classifier request rejected: <message>") would make this self-diagnosing.
Error Messages/Logs
[WARN] [Stall] classifier_request_finished ... stage=xml_s1 outcome=error errorKind=Error:400
[WARN] Auto mode classifier (XML) error: 400 {"type":"error","error":{"type":"invalid_request_error","message":"A maximum of 4 blocks with cache_control may be provided. Found 5."}}
[WARN] Got error trying Sonnet 5 as auto mode classifier, using claude-opus-5[1m]
[WARN] Auto mode classifier unavailable, denying with retry guidance (fail closed)
User-visible message:
claude-opus-5[1m] is temporarily unavailable, so auto mode cannot determine the safety of
Bash right now.
Model names carry a [1m] suffix because this setup points ANTHROPIC_BASE_URL at a
gateway whose aliases include it. The 400 is the standard Anthropic API cache_control
limit, so it should be provider-independent.
Steps to Reproduce
- Work in a directory that has a CLAUDE.md (any content). This matters: an empty directory
such as /tmp does NOT reproduce, presumably because the extra cached context block is
what pushes the request from 4 to 5.
- Put the session in auto permission mode.
- Ask for a Bash command that is OUTSIDE the built-in read-only set, so the classifier is
actually the gate:
claude --permission-mode auto -p 'Use the Bash tool to run exactly: ln -sf /etc/hostname /tmp/x'
Do not test with echo/ls/cat — those are allowed without ever consulting the classifier,
so they succeed even while auto mode is broken and make the bug look absent.
- The action is denied with the "temporarily unavailable" message. To see the real cause:
CLAUDE_CODE_DEBUG_LOGS_DIR=/tmp/dbg claude --debug --permission-mode auto -p '...'
then grep the log for classifier_request. In VS Code the extension already runs with
--debug, so the same lines are in its output log.
- A/B on the same directory and command:
npx -y @anthropic-ai/claude-code@2.1.220 -> classifier outcome=ok, action runs
2.1.222 -> classifier 400 "Found 5", action denied
Session size is irrelevant: it reproduces on a brand-new session (15 transcript entries) and
on a long one alike.
Claude Model
Opus
Is this a regression?
Yes, this worked in a previous version
Last Working Version
2.1.220
Claude Code Version
2.1.222 (Claude Code); also reproduced with the VS Code extension 2.1.223 and its bundled binary
Platform
Anthropic API
Operating System
Ubuntu/Debian Linux
Terminal/Shell
VS Code integrated terminal
Additional Information
Regression A/B (same directory, same settings, same command):
| Version | Classifier | Result |
|---|---|---|
| 2.1.220 (npx) | outcome=ok | action runs |
| 2.1.222 | 400 "Found 5" | action denied, fail closed |
Two notes that may help triage:
- CLAUDE_CODE_AUTO_MODE_MODEL appears to be unread in 2.1.22x. I set it in the real process
environment and the classifier still used the same model, so pinning a different classifier
is not available as a workaround.
- This may be the same underlying problem as #49535 ("auto mode classifier unavailable"),
where the suggested workaround is switching to acceptEdits. Downgrading to 2.1.220 also
restores it.
3 Comments
Still reproduces on 2.1.226 (and by inclusion 2.1.224 / 2.1.225 — none of their
changelog entries mention this).
Re-ran the exact A/B from the report today, same directory (has CLAUDE.md /
auto-memory context), same probe command, both via
npxso nothing is installed:| Version | Classifier | Result |
|---|---|---|
|
npx -y @anthropic-ai/claude-code@2.1.220|stage=xml_s1 outcome=ok| action runs ||
npx -y @anthropic-ai/claude-code@2.1.226| 400"A maximum of 4 blocks with cache_control may be provided. Found 5."| denied, fail closed |On 2.1.226 the 400 hits the first attempt and the fallback alike
(
model=claude-sonnet-5[1m] stage=xml_s1 → Error:400, thenmodel=claude-opus-5[1m] stage=xml_s1 → Error:400), so auto mode is fullyunavailable in any directory with project context.
One more data point: the npm dist-tag
stablecurrently points at 2.1.220 whilelatestis 2.1.226 — consistent with 2.1.220 being the last version where theclassifier request stays within the 4-block limit.
Happy to re-test when a fix lands.
Correction to my Aug 17 comment — the "context drift" attribution was wrong. The mechanism
is now pinned down, partly from the shipped binaries (all npm-fetchable), and it makes this
issue narrower and more actionable than either of my earlier comments suggested.
What was wrong. I attributed "can no longer reproduce" to our workspace context having
drifted back under the breakpoint threshold. Two facts kill that:
2.1.226tarball, same directory, same probe —failed with
Found 5on Aug 8, passed on Aug 17. The variable cannot be in the tarball,nor in "CLI construction × our context" if that construction is deterministic (it is, see
below).
on Aug 13). If content size moved the block count, failures should have gotten more
likely, not vanished.
What the binaries show (strings-level inspection of the linux-x64 packages for 2.1.220,
2.1.226, 2.1.233):
2.1.220: no transcript-tail breakpoint — zero co-occurrence of.at(-1)withcache_control.2.1.226: exactly one —...L=y.at(-1);if(L!==void 0)L.cache_control=M...2.1.233: the byte-for-byte same construct under different minified names(
...D=y.at(-1);if(D!==void 0)D.cache_control=P...).So with a CLAUDE.md present, the classifier request carries exactly 4
cache_controlblocks from 2.1.222 onward — the API's documented maximum, zero headroom — and nothing in
2.1.227–2.1.233 changed that. (2.1.220 carried 3, i.e. one unit of headroom.)
Reconciled timeline. On the failing days something outside the CLI construction was
contributing one extra
cache_controlblock (in our setup the candidates are proxy-sideinjection or config-delivered extra body params; a raw-request probe of our endpoint today
shows it clean — 4 blocks → 200, 5 → 400). That external block has since disappeared, which
is why the same tarball now passes. The client regression is therefore not "builds 5":
2.1.222 spent the last unit of headroom, so any environment that adds one block anywhere
in the path kills auto mode fail-closed — and it presents as "<model> is temporarily
unavailable", which is what makes it expensive to diagnose.
Asks, unchanged but sharper:
cache_controlbreakpoints client-side to the documented limit (there iscurrently no counting/pruning anywhere in the classifier path) — running at exactly the
maximum makes every proxy, gateway, or server-delivered body-param addition fatal.
invalid_request_erroras what it is instead of a model-availabilitymessage.
We remain pinned at 2.1.220 until a clamp ships.
Two updates: the regression has a narrower origin than my report said, and 2.1.258
still ships it.
The regression is 2.1.221, not 2.1.222. My A/B jumped 220 → 222 and skipped the
version in between. 2.1.221's changelog has it in plain sight:
That is the transcript-tail breakpoint. So this was a deliberate cache optimisation
that shipped without a budget check — not an accidental extra block. Which makes the
ask cheaper than I framed it: keep the 2.1.221 optimisation, add the clamp. Nobody
has to choose between cache cost and correctness.
Still unfixed in 2.1.258 (linux-x64, same strings-level inspection):
Same construct as 2.1.226/2.1.233 under new minified names. Full accounting of the
classifier request with a CLAUDE.md present, unchanged since 2.1.221:
| # | block | removable? |
|---|---|---|
| 1 | classifier system prompt, first block (the Session Context block carries none) | no |
| 2 | the
<user_claude_md>block | yes — this is why an empty dir doesn't reproduce || 3 | transcript tail,
.at(-1)(added in 2.1.221) | no || 4 | the action block | no |
Four of four, zero headroom, and still no counting or pruning anywhere on the path
(
side_queryrequest assembly → system-block assembly → messages passed throughuntouched; the 1h-TTL mapper only adds
ttlto blocks that already carrycache_control, it never introduces one).On the second ask — 2.1.246 shipped "Fixed auto mode tool calls being denied as
'temporarily unavailable' on very large sessions by scaling the safety-check deadline
with prompt size". So the same misleading string has already been addressed for a
different root cause. The 400
invalid_request_errorpath still reports modelavailability. That one is checkable in a minute and needs no repro.
For anyone hitting this before a clamp ships: block #2 is the lever. Moving CLAUDE.md
out of the working directory drops the request to 3 breakpoints and auto mode comes
straight back — cheaper than abandoning auto mode. The tell is
errorKind=Error:400plus
Found 5in the debug log; a denial that carries a<reason>is the classifierworking normally, not this bug.