Preflight Checklist
What's Wrong?
Summary
When a session crosses from included plan usage into Extra Usage, the client begins emitting ttl: "5m" cache_control blocks while earlier blocks in the same request are still marked ttl: "1h". The API rejects this ordering, and the session dies with a 400. It is not recoverable in-place — the conversation cannot continue.
This is distinct from the cost-regression complaint in #43566 (closed as not planned). That issue argues the 1h → 5m downgrade on overage is bad policy. This report is narrower and does not depend on that argument: whatever the intended TTL policy is, the client should never construct a request whose cache_control blocks violate the API's own ordering constraint. The result is a crash, not an efficiency loss.
Impact
Session-fatal, and it fires precisely when a user has just started paying extra to keep working. Two of my concurrent sessions died at the same moment — the instant the limit was crossed — so any long-running work in flight at that boundary is lost. The failure mode is also confusing from the user side: Extra Usage is enabled and funded, so the expectation is that work continues, but every subsequent request 400s.
Observed errors
Two sessions, same boundary, different message indices:
API Error: 400 messages.46.content.0.cache_control.ttl: a ttl='1h'
cache_control block must not come after a ttl='5m' cache_control block.
Note that blocks are processed in the following order: tools, system,
messages.
API Error: 400 messages.190.content.1.cache_control.ttl: a ttl='1h'
cache_control block must not come after a ttl='5m' cache_control block.
Note that blocks are processed in the following order: tools, system,
messages.
The differing indices (46 and 190) indicate this is not tied to a specific conversation length or position — it tracks the overage transition, not the message count.
Reproduction
Start a session with Extra Usage enabled on the account.
Work in it long enough to build up cached context under the 1h TTL.
Exhaust the included plan usage so Extra Usage activates mid-session.
Send another turn.
Expected: the turn completes, billed to Extra Usage. Actual: 400 on the cache_control TTL ordering, and every subsequent turn in that session fails the same way.
Root cause (per #43566's analysis)
The overage check that gates whether ttl: "1h" is requested flips partway through a session. Blocks written before the flip carry 1h; blocks written after carry the 5m default. Because the API requires all 1h blocks to precede any 5m block, a request that mixes both in the wrong order is invalid — and the mixed state is the normal consequence of the flip happening mid-conversation.
Expected behavior
At minimum, the TTL decision should be consistent within a single request. Some options, roughly in order of how much they change:
Evaluate the overage state once per request and apply the resulting TTL uniformly to every cache_control block in that request, rather than letting it change between blocks.
If the TTL must change when overage activates, drop the cache markers and rebuild them cleanly on the next request rather than emitting a mixed set.
Failing either, catch this specific 400 and retry once with a uniform TTL, so the session degrades in cost rather than dying.
Separately, and as a policy question rather than a bug: keeping the 1h TTL on overage requests would avoid the whole class of problem, and #43566 makes a reasonable case that it is also cheaper for the user.
Environment
Client: Claude Code CLI
Version: 2.1.222
Plan: Max (5x) with Extra Usage enabled
OS: macOS 26.6
Approximate time of failure: 2026-08-04 ~13:45 UTC (22:45 JST, UTC+9)
Related
#43566 — TTL downgrade on Extra Usage (closed as not planned)
#46829 — earlier cache TTL regression (closed as not planned)
#60316 — request to expose TTL as a configurable setting
cnighswonger/claude-code-cache-fix#44 — the same 400 reported against a community proxy built to work around this area
What Should Happen?
The turn completes and is billed to Extra Usage.
Concretely, the cache TTL should be uniform within a single request: the
overage state should be evaluated once per request and applied to every
cache_control block in it, rather than being re-evaluated per block so that
some blocks carry 1h and later ones carry 5m. When the overage state does
flip mid-session, the client should rebuild its cache markers cleanly at the
new TTL instead of emitting a mixed set that violates the API's own ordering
constraint.
Whatever the intended TTL policy is on overage, a change in internal billing
state should never render an in-progress session permanently unusable. At
minimum this specific 400 should be caught and retried once with a uniform
TTL, so the failure degrades into higher cost rather than a dead session.
Error Messages/Logs
Two independent sessions, same account, failed within the same minute of
each other at the point Extra Usage activated. Errors verbatim:
Session A:
API Error: 400 messages.46.content.0.cache_control.ttl: a ttl='1h'
cache_control block must not come after a ttl='5m' cache_control block.
Note that blocks are processed in the following order: `tools`, `system`,
`messages`.
Session B:
API Error: 400 messages.190.content.1.cache_control.ttl: a ttl='1h'
cache_control block must not come after a ttl='5m' cache_control block.
Note that blocks are processed in the following order: `tools`, `system`,
`messages`.
Identical error, different message indices (46 / 190) and different content
indices (0 / 1). Both sessions then failed on every subsequent turn with the
same error until abandoned.
Steps to Reproduce
- Use an account where Extra Usage is enabled and included plan usage is
close to exhausted.
- Start a session and work in it long enough to build substantial cached
context (cache_control blocks written with ttl: "1h").
- Keep working until included usage is exhausted and Extra Usage activates
mid-session, i.e. without restarting the session.
- Send one more turn.
The turn fails with a 400 on cache_control TTL ordering. Every subsequent
turn in that session fails identically. The session cannot be recovered in
place; only starting a new session clears it.
Notes on determinism: this fired on two independent concurrent sessions
within the same minute of each other, at different message indices (46 and
190). That points at the account-level usage transition as the trigger
rather than anything in either conversation — conversation length and
content were unrelated. Anyone able to force an account into overage
mid-session should be able to reproduce it on demand.
Claude Model
Other
Is this a regression?
I don't know
Last Working Version
No response
Claude Code Version
2.1.222
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
No response
Preflight Checklist
What's Wrong?
Summary
When a session crosses from included plan usage into Extra Usage, the client begins emitting ttl: "5m" cache_control blocks while earlier blocks in the same request are still marked ttl: "1h". The API rejects this ordering, and the session dies with a 400. It is not recoverable in-place — the conversation cannot continue.
This is distinct from the cost-regression complaint in #43566 (closed as not planned). That issue argues the 1h → 5m downgrade on overage is bad policy. This report is narrower and does not depend on that argument: whatever the intended TTL policy is, the client should never construct a request whose cache_control blocks violate the API's own ordering constraint. The result is a crash, not an efficiency loss.
Impact
Session-fatal, and it fires precisely when a user has just started paying extra to keep working. Two of my concurrent sessions died at the same moment — the instant the limit was crossed — so any long-running work in flight at that boundary is lost. The failure mode is also confusing from the user side: Extra Usage is enabled and funded, so the expectation is that work continues, but every subsequent request 400s.
Observed errors
Two sessions, same boundary, different message indices:
API Error: 400 messages.46.content.0.cache_control.ttl: a ttl='1h'
cache_control block must not come after a ttl='5m' cache_control block.
Note that blocks are processed in the following order:
tools,system,messages.API Error: 400 messages.190.content.1.cache_control.ttl: a ttl='1h'
cache_control block must not come after a ttl='5m' cache_control block.
Note that blocks are processed in the following order:
tools,system,messages.The differing indices (46 and 190) indicate this is not tied to a specific conversation length or position — it tracks the overage transition, not the message count.
Reproduction
Start a session with Extra Usage enabled on the account.
Work in it long enough to build up cached context under the 1h TTL.
Exhaust the included plan usage so Extra Usage activates mid-session.
Send another turn.
Expected: the turn completes, billed to Extra Usage. Actual: 400 on the cache_control TTL ordering, and every subsequent turn in that session fails the same way.
Root cause (per #43566's analysis)
The overage check that gates whether ttl: "1h" is requested flips partway through a session. Blocks written before the flip carry 1h; blocks written after carry the 5m default. Because the API requires all 1h blocks to precede any 5m block, a request that mixes both in the wrong order is invalid — and the mixed state is the normal consequence of the flip happening mid-conversation.
Expected behavior
At minimum, the TTL decision should be consistent within a single request. Some options, roughly in order of how much they change:
Evaluate the overage state once per request and apply the resulting TTL uniformly to every cache_control block in that request, rather than letting it change between blocks.
If the TTL must change when overage activates, drop the cache markers and rebuild them cleanly on the next request rather than emitting a mixed set.
Failing either, catch this specific 400 and retry once with a uniform TTL, so the session degrades in cost rather than dying.
Separately, and as a policy question rather than a bug: keeping the 1h TTL on overage requests would avoid the whole class of problem, and #43566 makes a reasonable case that it is also cheaper for the user.
Environment
Client: Claude Code CLI
Version: 2.1.222
Plan: Max (5x) with Extra Usage enabled
OS: macOS 26.6
Approximate time of failure: 2026-08-04 ~13:45 UTC (22:45 JST, UTC+9)
Related
#43566 — TTL downgrade on Extra Usage (closed as not planned)
#46829 — earlier cache TTL regression (closed as not planned)
#60316 — request to expose TTL as a configurable setting
cnighswonger/claude-code-cache-fix#44 — the same 400 reported against a community proxy built to work around this area
What Should Happen?
The turn completes and is billed to Extra Usage.
Concretely, the cache TTL should be uniform within a single request: the
overage state should be evaluated once per request and applied to every
cache_control block in it, rather than being re-evaluated per block so that
some blocks carry 1h and later ones carry 5m. When the overage state does
flip mid-session, the client should rebuild its cache markers cleanly at the
new TTL instead of emitting a mixed set that violates the API's own ordering
constraint.
Whatever the intended TTL policy is on overage, a change in internal billing
state should never render an in-progress session permanently unusable. At
minimum this specific 400 should be caught and retried once with a uniform
TTL, so the failure degrades into higher cost rather than a dead session.
Error Messages/Logs
Steps to Reproduce
close to exhausted.
context (cache_control blocks written with ttl: "1h").
mid-session, i.e. without restarting the session.
The turn fails with a 400 on cache_control TTL ordering. Every subsequent
turn in that session fails identically. The session cannot be recovered in
place; only starting a new session clears it.
Notes on determinism: this fired on two independent concurrent sessions
within the same minute of each other, at different message indices (46 and
190). That points at the account-level usage transition as the trigger
rather than anything in either conversation — conversation length and
content were unrelated. Anyone able to force an account into overage
mid-session should be able to reproduce it on demand.
Claude Model
Other
Is this a regression?
I don't know
Last Working Version
No response
Claude Code Version
2.1.222
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
No response