[BUG] Auto mode classifier builds 5 cache_control blocks → API 400, surfaced as "<model> is temporarily unavailable" (regression 2.1.220 → 2.1.222)

Status Open
Reported on v2.1.222
Maintainer reply None cached
Activity 3 comments · opened Aug 7, 2026

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:

  1. 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.

  1. 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

  1. 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.

  1. Put the session in auto permission mode.
  1. 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.

  1. 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.

  1. 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.

View original on GitHub ↗

3 Comments

fongcap-001 · 2 months ago

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 npx so 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, then
model=claude-opus-5[1m] stage=xml_s1 → Error:400), so auto mode is fully
unavailable in any directory with project context.

One more data point: the npm dist-tag stable currently points at 2.1.220 while
latest is 2.1.226 — consistent with 2.1.220 being the last version where the
classifier request stays within the 4-block limit.

Happy to re-test when a fix lands.

fongcap-001 · 2 months ago

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:

  1. Same bytes, two outcomes: the identical 2.1.226 tarball, same directory, same probe —

failed with Found 5 on 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).

  1. Our context files grew between those dates (new sections added to CLAUDE.md and memory

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) with

cache_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_control
blocks 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_control block (in our setup the candidates are proxy-side
injection 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:

  1. Clamp/prune cache_control breakpoints client-side to the documented limit (there is

currently no counting/pruning anywhere in the classifier path) — running at exactly the
maximum makes every proxy, gateway, or server-delivered body-param addition fatal.

  1. Surface the 400 invalid_request_error as what it is instead of a model-availability

message.

We remain pinned at 2.1.220 until a clamp ships.

fongcap-001 · 1 month ago

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:

- Reduced prompt-cache costs for auto-mode permission checks by reusing the cached conversation prefix across decisions - Improved auto mode: permission checks for parallel tool calls are now cache-efficient

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):

ht=oO({ttl:ySt()}),It=ye.at(-1);if(It!==void 0)It.cache_control=ht;
...
ye.push({type:"text",text:k,cache_control:ht});

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_query request assembly → system-block assembly → messages passed through
untouched; the 1h-TTL mapper only adds ttl to blocks that already carry
cache_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_error path still reports model
availability. 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:400
plus Found 5 in the debug log; a denial that carries a <reason> is the classifier
working normally, not this bug.