[BUG] Interactive sessions write the 5-minute prompt cache despite requesting 1h: `cache-keepalive-2026-09-03` beta (2.1.296–2.1.300, Team and Max; `claude -p` unaffected)
What's wrong
Since 2026-10-12 at about 18:18 UTC, every newly started interactive session writes its main-conversation prompt cache under the 5-minute TTL. Headless claude -p runs on the same account, machine, version and model still write under 1 hour. The account is a subscription within its included usage, so per the prompt-caching docs both should get 1 hour. Interactive turns, -p runs and SDK turns are documented as the same "main conversation" bucket.
Evidence (from local transcripts, message.usage.cache_creation on non-sidechain assistant rows)
| Case | Entrypoint | Result |
|---|---|---|
| Interactive sessions started before 2026-10-12 18:18 UTC | cli | 1h; they kept writing 1h until they went idle (last at 19:56 UTC) |
| Every interactive session started after 18:18 UTC (5 sessions) | cli | 5m from the first turn, 1h always 0 |
| claude -p runs after 18:18 UTC (4 runs, latest 2026-10-13 04:54 UTC) | sdk-cli | 1h |
| Interactive session in a plain terminal, outside tmux and any launcher (2026-10-13 05:05 UTC) | cli | 5m |
| Interactive session after /login re-authentication (2026-10-13 05:08 UTC) | cli | 5m |
- No session ever changed bucket partway through, across 14 sessions, so the TTL looks fixed at session start.
usagemetadata is identical on 1h and 5m rows:service_tier: "standard",speed: "standard",fallback_credit: null.- In the transcripts from the four days up to the onset (2026-10-09 to 2026-10-12 18:18 UTC), every main-thread cache write was 1h.
Environment
- Claude Code 2.1.296 (native install) on Linux (WSL2); model
claude-opus-5-5. The same version was in use on both sides of the onset - Auth: claude.ai subscription via
/login(OAuth). Team seatteam_tier_1; user rate-limit tierdefault_claude_max_5x ~/.claude.json:oauthAccount.hasExtraUsageEnabled: true,cachedExtraUsageDisabledReason: "out_of_credits"(still present after/login)- Not near the 5-hour or weekly limits
- None set:
ANTHROPIC_API_KEY,CLAUDE_CODE_USE_*,CLAUDE_CODE_OAUTH_TOKEN,CLAUDE_CODE_PROMPT_CACHE_TTL,FORCE_PROMPT_CACHING_5M,ENABLE_PROMPT_CACHING_1H,DISABLE_TELEMETRY,CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC. NopromptCacheTtlin user or managed settings - Cached
tengu_prompt_cache_1h_config.allowliststill includesrepl_main_thread*andsdk
Steps to reproduce (on an affected account)
- Run
claudeinteractively, send one turn and exit. - Run
claude -p "Reply with OK"in the same directory. - Compare the buckets:
``sh`
jq -c 'select(.type=="assistant" and .isSidechain!=true and .message.usage.cache_creation)
| [.timestamp, .entrypoint, .message.usage.cache_creation.ephemeral_1h_input_tokens,
.message.usage.cache_creation.ephemeral_5m_input_tokens]' ~/.claude/projects/<dir>/<session>.jsonl
[...,"cli",0,N]
Interactive shows and -p shows [...,"sdk-cli",N,0]`.
Expected
Interactive sessions on a subscription within included usage write the main conversation under the 1-hour TTL, as -p does.
Possibly related
- #46829: Anthropic support described an overage-latch bug, fixed in 2.1.90, in which a session started while the seat was in overage kept 5m on the main loop. The latch-at-start shape matches this report, but this seat is not in overage.
- #79337, #80749, #93840: the interactive client misjudged usage-credit entitlement while
-pworked on the same account. One investigator traced it to per-session flag evaluation, and one report involvedout_of_credits.
Question
Does the interactive startup path consult usage-credit state (here, an org-level out_of_credits) when choosing the main-conversation TTL, and treat it as "drawing on usage credits"? Or has the overage latch regressed?
9 Comments
Reproduced by a second user in the same Team org, 2026-10-13.
claude-opus-5-5, entrypointcli(interactive).ephemeral_5m_input_tokens> 0 andephemeral_1h_input_tokens: 0, from the first turn.One extra data point: the harness system prompt in that same session tells the model the session "uses a 1-hour Anthropic prompt-cache TTL". So the client appears to believe it is requesting 1h, while the usage shows 5m writes. That points to the request being sent or handled differently, not to the account being in usage overage.
Checked with:
Follow-up from the reporter's side:
"promptCacheTtl": "1h"switches a running interactive session toephemeral_1hwrites within seconds. The interactive client's default TTL choice is what lands on 5m, even though the system prompt says "1-hour TTL".cachedExtraUsageDisabledReasonwent fromout_of_creditstoorg_level_disabled), a fresh interactive session with user settings excluded (--setting-sources project,local) still wrote 5m.Same symptom here, with a data point on behavior rather than just the label. Claude Code 2.1.296, Linux, Team seat, interactive
clisessions. Our 1h writes ended around 2026-10-12 15:15 CT, and 5m writes have continued since (a few sessions between about 14:00 and 15:10 CT that day were still 1h, so onset wasn't clean for us). Headlesssdk-cliruns on the morning of 10-13 were still 1h. No TTL setting or env var is set, and/usageshowed 39% of the session and 7% of the week used.To test whether the 5m label matches behavior, I ran a controlled probe: a background session in an empty directory with three one-shot cron wakes, each a tiny no-tool turn. All writes were labeled
ephemeral_5m:| Idle before wake | cache_read | cache_write |
|---|---|---|
| 13.4 min | 56,368 | 30 |
| 30.0 min | 56,398 | 28 |
| 70.0 min | 27,378 (shared prefix only) | 29,076 |
So 5m-labeled writes survived 30 minutes and expired by 70, which looks like a 1h-like lifetime under a 5m label. The 27,378 read at 70 minutes is the same shared system-prompt prefix the probe's first call read, so the conversation itself was rebuilt. Interactive sessions on 10-12 and 10-13 show the same: idle gaps of 5–20 minutes and one of about 30 with full cache reads despite 5m labels.
Same here, with a later onset. Linux (WSL2), Team seat, interactive
cli:ephemeral_1h, the last at 14:03 UTC.ephemeral_5mfrom its first turn, on both 2.1.296 and 2.1.299. So it's not tied to the client version, and 2.1.299 doesn't fix it.claude -pruns that morning still wrote 1h."promptCacheTtl": "1h"switched all three running sessions (2.1.296 and 2.1.299) toephemeral_1hon their next turn, without a restart.Same symptom on macOS, Claude Code 2.1.296 and 2.1.299, model
claude-opus-5-5, interactivecli. Two data points that the reports above do not have yet:ANTHROPIC_LOG=debug. Its startupquota_checkresponse returned:anthropic-ratelimit-unified-status: allowed_warninganthropic-ratelimit-unified-5h-status: allowed(utilization 0.27)anthropic-ratelimit-unified-7d-status: allowed_warning(utilization 0.85, surpassed threshold 0.75)anthropic-ratelimit-unified-overage-status: allowedThe main status is not
rejected, so the session is not drawing on overage. Its first main-thread turn still wrote onlyephemeral_5m.out_of_credits.~/.claude.jsonhasoauthAccount.hasExtraUsageEnabled: trueandcachedExtraUsageDisabledReason: null. So that state is not the trigger here either.Onset on this machine: interactive sessions started before about 2026-10-13 17:00 UTC wrote 1h. Sessions started after that wrote 5m from the first turn. One session that wrote 1h in the afternoon wrote 5m when it continued after a gap of several hours.
Today, on the same account:
claude -pwrites 1h, with and without plugins loaded. An interactive session started with--settings '{"promptCacheTtl":"1h"}'writes 1h from its first turn.Same here: macOS, Max subscription,
claude-opus-5-5, interactivecli, no TTL env vars or settings. I'm far from my 5h and 7d limits.Main-thread cache writes from my local transcripts, Oct 11–14:
| Version | Sessions | Cache writes |
| ------- | --------------------------- | ----------------------------------------- |
| 2.1.296 | 4 (Oct 11–13) | all
ephemeral_1h|| 2.1.299 | 1 (Oct 14, 15:40–19:23 UTC) | all
ephemeral_1h, through its last turn || 2.1.300 | 3 (Oct 14, from 18:06 UTC) | all
ephemeral_5mfrom the first turn |The 2.1.299 session kept writing 1h for more than an hour after new 2.1.300 sessions had started writing 5m. Others here hit this on 2.1.296 and 2.1.299 too, so the version may not be the trigger. But on my machine the TTL looks fixed when the session starts rather than chosen per request.
As others noted, the system prompt in the affected session still says requests use a 1-hour TTL, so the client seems to think it's asking for 1h. Setting
"promptCacheTtl": "1h"explicitly is my workaround for now.asking claude why my status line isn't showing 1h cache expiry progress bar anymore bring me here lol.
but it seems they already fixed it now, because my progress bar has appeared again just when i about comment here.
Cause found (reporter's side, 2026-10-15, Claude Code 2.1.300). I intercepted my own client's API traffic (mitmproxy, local, my own account, request structure only) and changed one thing at a time. Each run used a clean environment with user settings excluded, an empty directory and one "Reply with OK" turn.
| Run | Client requests |
cache-keepalive-2026-09-03beta | Server writes ||---|---|---|---|
| Default interactive (×3) |
ttl: "1h"on all 3 breakpoints | sent | 5m (1h = 0) || Same, with only that beta removed in flight (×2) |
ttl: "1h"| removed | 1h (5m = 0) || Interactive with
promptCacheTtl: "1h"|ttl: "1h"| not sent | 1h ||
claude -p|ttl: "1h"| not sent | 1h |The client still asks for 1h. When the request carries the
cache-keepalive-2026-09-03beta, the server records the write as 5m. That accounts for three things in this thread:claude -pnever sends the beta.promptCacheTtl: "1h"works around it: with an explicit TTL the client stops sending the beta.The keepalive itself. While idle, the client sends
POST /v1/messages/cache_touchevery 30 s. I left one session idle for 11.5 min (23 touches, all 204). The next turn first tried a server-side thread continuation (message-threads-2026-08-12beta) and got404 thread_not_found("No thread state was found for the requestedprevious_message_id…"). The client then replayed the full conversation. Only the system prefix (31,157 tokens, shared with other sessions) came from cache, and the conversation part was written again at 5m. That is a single run, so it isn't conclusive, but in that run the touches did not keep the conversation cache alive past about 11 minutes.Testing caveat: pointing
ANTHROPIC_BASE_URLat a logging proxy hides the bug. With a custom base URL the client skips the first-party flag and bootstrap calls and doesn't send the beta, so everything writes 1h. UseHTTPS_PROXYwith a trusted CA instead.Still affected here: a default interactive session at 12:16 UTC today (2.1.300) still wrote 5m (13,551 tokens; 1h = 0), so whatever changed for the comment above hasn't reached this account.
Question for maintainers: is the keepalive meant to override an explicit
ttl: "1h"? If the touches don't survive an ordinary idle gap, interactive users lose the 1h cache they had before, and spend more of their usage limits on rewrites.Same here: macOS, Team seat,
claude-opus-5-5, interactivecli, well within limits (2% session / 24% week, no overage in/usage). No TTL env vars or settings.Onset 2026-10-15 ~19:45 UTC, latched per session start:
| Session started | Version | Main-thread writes |
|---|---|---|
| before 18:12 UTC (several) | 2.1.300 |
ephemeral_1h|| ~19:50 UTC | 2.1.300 |
ephemeral_1h, still 1h the next morning || 19:47, 20:55, 21:02 UTC | 2.1.300 |
ephemeral_5mfrom the first turn || after 20:55 UTC | 2.1.301 |
ephemeral_5mfrom the first turn |Confirms the flag correlation from #102338. Two accounts on the same machine and the same binary:
cachedGrowthBookFeatures.tengu_sequential_cloud={"enabled":true,"touchIntervalSeconds":30,"activityWindowMinutes":60,"resumeTouches":true}-> 5mtengu_sequential_cloud=false-> 1h"promptCacheTtl": "1h"insettings.jsonswitched a running affected session toephemeral_1hon its next request (one full rewrite, ~52k tokens), no restart needed.