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

Status Open
Reported on v2.1.296
Maintainer reply None cached
Activity 9 comments · opened Oct 13, 2026

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.
  • usage metadata 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 seat team_tier_1; user rate-limit tier default_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. No promptCacheTtl in user or managed settings
  • Cached tengu_prompt_cache_1h_config.allowlist still includes repl_main_thread* and sdk

Steps to reproduce (on an affected account)

  1. Run claude interactively, send one turn and exit.
  2. Run claude -p "Reply with OK" in the same directory.
  3. 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
`
Interactive shows
[...,"cli",0,N] 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 -p worked on the same account. One investigator traced it to per-session flag evaluation, and one report involved out_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?

View original on GitHub ↗

9 Comments

bhasmang-tri · 2 days ago

Reproduced by a second user in the same Team org, 2026-10-13.

  • Claude Code 2.1.296, macOS (Darwin 25.3.0), model claude-opus-5-5, entrypoint cli (interactive).
  • New interactive session: every assistant row in the transcript shows ephemeral_5m_input_tokens > 0 and ephemeral_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:

grep -o '"cache_creation":{[^}]*}' ~/.claude/projects/<project>/<session>.jsonl | tail
chrs-myrs · 2 days ago

Follow-up from the reporter's side:

  • Same org: @bhasmang-tri's repro is a second seat in the same Team org, on macOS, so this isn't WSL-specific.
  • The API honours an explicit 1h: setting "promptCacheTtl": "1h" switches a running interactive session to ephemeral_1h writes within seconds. The interactive client's default TTL choice is what lands on 5m, even though the system prompt says "1-hour TTL".
  • Org usage credits aren't the trigger: after we turned usage credits off at org level (cachedExtraUsageDisabledReason went from out_of_credits to org_level_disabled), a fresh interactive session with user settings excluded (--setting-sources project,local) still wrote 5m.
jaredrhall · 2 days ago

Same symptom here, with a data point on behavior rather than just the label. Claude Code 2.1.296, Linux, Team seat, interactive cli sessions. 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). Headless sdk-cli runs on the morning of 10-13 were still 1h. No TTL setting or env var is set, and /usage showed 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.

ist-shd · 1 day ago

Same here, with a later onset. Linux (WSL2), Team seat, interactive cli:

  • Every interactive session on 2026-10-13 (8 sessions, 2.1.296) wrote ephemeral_1h, the last at 14:03 UTC.
  • From 2026-10-14 04:59 UTC (first session after an overnight gap), every new interactive session wrote ephemeral_5m from 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 -p runs that morning still wrote 1h.
  • Adding "promptCacheTtl": "1h" switched all three running sessions (2.1.296 and 2.1.299) to ephemeral_1h on their next turn, without a restart.
sypsyp97 · 1 day ago

Same symptom on macOS, Claude Code 2.1.296 and 2.1.299, model claude-opus-5-5, interactive cli. Two data points that the reports above do not have yet:

  1. The response headers show no overage. I started an affected interactive session with ANTHROPIC_LOG=debug. Its startup quota_check response returned:
  • anthropic-ratelimit-unified-status: allowed_warning
  • anthropic-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: allowed

The main status is not rejected, so the session is not drawing on overage. Its first main-thread turn still wrote only ephemeral_5m.

  1. The usage-credit state is not out_of_credits. ~/.claude.json has oauthAccount.hasExtraUsageEnabled: true and cachedExtraUsageDisabledReason: 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 -p writes 1h, with and without plugins loaded. An interactive session started with --settings '{"promptCacheTtl":"1h"}' writes 1h from its first turn.

mourner · 1 day ago

Same here: macOS, Max subscription, claude-opus-5-5, interactive cli, 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_5m from 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.

brofids · 17 hours ago

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.

chrs-myrs · 17 hours ago

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-03 beta | 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-03 beta, the server records the write as 5m. That accounts for three things in this thread:

  • Interactive vs headless: claude -p never sends the beta.
  • Why promptCacheTtl: "1h" works around it: with an explicit TTL the client stops sending the beta.
  • Staggered onset across accounts: the beta looks like it is switched on per account by a remote flag. I haven't identified which flag.

The keepalive itself. While idle, the client sends POST /v1/messages/cache_touch every 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-12 beta) and got 404 thread_not_found ("No thread state was found for the requested previous_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_URL at 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. Use HTTPS_PROXY with 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.

ArnelsPretty · 38 minutes ago

Same here: macOS, Team seat, claude-opus-5-5, interactive cli, 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_5m from the first turn |
| after 20:55 UTC | 2.1.301 | ephemeral_5m from the first turn |

Confirms the flag correlation from #102338. Two accounts on the same machine and the same binary:

  • Team account: cachedGrowthBookFeatures.tengu_sequential_cloud = {"enabled":true,"touchIntervalSeconds":30,"activityWindowMinutes":60,"resumeTouches":true} -> 5m
  • Personal account: tengu_sequential_cloud = false -> 1h

"promptCacheTtl": "1h" in settings.json switched a running affected session to ephemeral_1h on its next request (one full rewrite, ~52k tokens), no restart needed.