[BUG] Context silently loses 157K tokens with no compaction record, then prompt cache thrashes for 17 minutes
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?
Context silently loses 157K tokens with no compaction record, then prompt cache thrashes for 17 minutes — 21 full-context rewrites, ~25M tokens burned
Environment
| | |
|---|---|
| Claude Code version | 2.1.247 |
| Entrypoint | claude-desktop |
| Model | claude-opus-5 |
| OS | Windows 11 (10.0.26200) |
| Session ID | SESSION-A |
| Date of incident | 2026-08-29, 03:17:43 → 03:34:43 UTC (06:17:43 → 06:34:43 UTC+3) |
| Cache TTL in use | ephemeral_1h on every affected turn |
Summary
At 06:17:43 the conversation context dropped by 157,023 tokens (829,414 -> 672,391) with
no compaction record, no context-editing record, and no error in the session transcript.
Immediately afterwards the prompt cache began thrashing: the session performed 21 full-context
rewrites in 17 minutes, including 19 consecutive rewrites with zero cache hits, before
recovering on its own.
Two things appear wrong here: (1) context was mutated with nothing recorded to explain it, and
(2) the cache never re-stabilised afterwards for 17 minutes despite the context being otherwise
static and growing normally.
Each rewrite re-wrote ~628,000 tokens. On every single failed turn cache_read_input_tokens
was frozen at exactly 45,659 — the system-prompt prefix only — meaning the cache was being
written and then never read back.
The work being done during this period was trivial: Read and Bash calls averaging ~680
output tokens per turn.
Timeline (all 27 turns, local UTC+3)
time context cache_creation cache_read output
06:16:56 829,414 851 828,561 160 healthy
06:17:43 672,391 626,730 45,659 1,050 <== 157,023 tokens vanish + rewrite #1
06:18:06 673,633 1,242 672,389 556 recovered
06:18:28 674,228 595 673,631 87 healthy
06:19:04 674,157 628,496 45,659 516 <== rewrite #2
06:19:21 674,743 586 674,155 160 recovered (last healthy turn)
06:19:47 673,837 628,176 45,659 293 <== rewrite #3
06:20:29 674,907 629,246 45,659 628 <== rewrite #4
06:21:08 678,184 632,523 45,659 843 <== rewrite #5
06:21:42 679,197 633,536 45,659 609 <== rewrite #6
06:22:19 674,175 628,514 45,659 799 <== rewrite #7
06:22:56 675,213 629,552 45,659 785 <== rewrite #8
06:23:32 668,826 623,165 45,659 352 <== rewrite #9
06:24:22 667,475 621,814 45,659 832 <== rewrite #10
06:25:00 669,819 624,158 45,659 796 <== rewrite #11
06:25:38 669,908 624,247 45,659 424 <== rewrite #12
06:26:27 669,314 623,653 45,659 716 <== rewrite #13
06:27:09 672,751 627,090 45,659 710 <== rewrite #14
06:27:55 672,419 626,758 45,659 285 <== rewrite #15
06:28:40 674,169 628,508 45,659 655 <== rewrite #16
06:29:19 676,392 630,731 45,659 707 <== rewrite #17
06:30:04 676,003 630,342 45,659 741 <== rewrite #18
06:30:44 679,585 633,924 45,659 698 <== rewrite #19
06:31:23 680,679 635,018 45,659 658 <== rewrite #20
06:32:00 680,375 634,714 45,659 1,231 <== rewrite #21
06:33:32 681,958 1,583 680,373 610 self-healed
06:33:54 682,624 666 681,956 329 healthy
06:34:43 683,029 405 682,622 1,696 healthy
What did NOT cause this
The session transcript rules out the obvious explanations:
Not an auto-compaction. The entire 1,237-turn session contains exactly two compactions,
both carrying a full compactMetadata record:
| when (UTC+3) | trigger | preTokens | postTokens |
|---|---|---|---|
| 2026-08-25 00:27:04 | auto | 1,000,701 | 10,194 |
| 2026-08-29 01:33:58 | auto | 999,497 | 12,371 |
Neither is near 06:17:43. Both reduce context to ~10-12K, not to 672K. Both recovered cleanly
(cache_creation of only ~23-25K on the following turn). Real compactions in this session behave
correctly.
Not API-side context editing. The only context_management payload in the session reports{"applied_edits": []} — no edits applied — and is timestamped 03:33:34, not 06:17:43.
Not TTL expiry. See below.
Not an API error. The session's single isApiErrorMessage entry is dated 2026-08-25 20:03:55.
So a 157,023-token removal occurred at 06:17:43 with nothing in the transcript accounting for
it. Debug logging was not enabled at the time, so client-side detail is unavailable.
Expected vs actual
Expected: whatever mutated the context invalidates the cached prefix once. One expensive
rebuild (~628K cache_creation), then every subsequent turn reads the new prefix from cache
(cache_read ≈ context size, cache_creation ≈ a few hundred tokens).
That is exactly what happened at 06:18:06 and 06:18:28 — so the rebuild did succeed, and the
cache was usable.
Actual: the cache was silently discarded again at 06:19:04 and, after one more brief recovery
at 06:19:21, discarded on 19 consecutive turns from 06:19:47 to 06:32:00. It then recovered
on its own at 06:33:32 with no user action and no change in context size.
On every one of the 21 failed turns cache_read_input_tokens was exactly 45,659 — the
system-prompt/tools prefix, i.e. only the first cache breakpoint matched while every breakpoint
after it missed. The turns in between show cache_read of 672,389 / 673,631 / 674,155, proving a
usable cache entry existed and was simply not being found.
Why TTL expiry does not explain this
- All 27 turns carry
cache_creation.ephemeral_1h_input_tokens— a 1-hour TTL. - The 21 rewrites span 17 minutes, at ~40 seconds between turns. No gap approaches the TTL.
- TTL expiry would produce one rewrite, not 21 with a frozen
cache_readvalue. ephemeral_5m_input_tokensis 0 on every affected turn; only the 1-hour tier was in use.
Impact
| | |
|---|---|
| Turns after 06:17:43 | 27 |
| Full-context rewrites | 21 |
| Total cache_creation | 13,200,895 tokens |
| Total output_tokens for those turns | 14,328 |
| Healthy per-turn cost (measured, same session, 05:20–06:16) | ~75,000 weighted tokens |
| Actual per-turn cost during failure | ~1,264,000 weighted tokens (~17x) |
| Effective tokens spent after 06:17:43 | ~27,003,000 |
| Effective tokens the same work should have cost | ~2,025,000 |
| Wasted | ~24,978,000 weighted tokens |
Weighting used: input×1 + cache_read×0.1 + cache_creation×2 + output×5.
This consumed roughly 36% of a full 5-hour usage window and counted against the weekly limit,
for ~14K tokens of actual output. The 5-hour quota hit 85% within ~20 minutes of the window
rolling over, which is what first surfaced the problem.
Control: a concurrent session that did NOT fail
Session SESSION-B (a different, unrelated project) ran in parallel on the
same machine, same account, same model, same Claude Code version, and never exhibited this:
| | Control session SESSION-B | Affected session SESSION-A |
|---|---|---|
| Transcript size | 147 MB | 78 MB |
| Peak context reached | 997,323 | 998,040 |
| Total turns | 2,435 | 1,237 |
| Turns with cache_creation > cache_read | 24 | 29 |
| Distribution of those turns | isolated, spread over 7 days | 21 clustered in 6 minutes |
| cache_creation / cache_read ratio, worst 20-min bucket | 0.04 | 3.95 |
The 24 events in the control session are single post-compaction rebuilds that immediately
recovered — the correct behavior. This rules out context size, transcript size, and account-level
state as the cause: the healthy session ran at a larger peak context with a larger transcript.
The control session also compacts regularly and never exhibits an unexplained partial context
drop of the kind seen at 06:17:43.
How to verify
The evidence is in the local transcript. Per-turn usage objects are recorded on type:"assistant"
entries in:
~/.claude/projects/<project-A>/<session-A>.jsonl
Filter to timestamp >= 2026-08-29T03:17:43Z and inspect cache_read_input_tokens — the constant
45,659 across 21 non-adjacent turns is the signature.
To confirm no compaction occurred, grep the same file for compactMetadata — only two matches
exist, dated 2026-08-24T21:27:04Z and 2026-08-28T22:33:58Z.
Note when parsing: deduplicate on message.id first (see secondary issue below).
---
Secondary issue: transcript double-logging inflates any local usage audit
In the same transcript, 785 of 1,237 distinct message.id values are written as 2–3 separate
JSONL entries, each with distinct uuid but identical usage payloads and identicalrequestId. Naive summation over type:"assistant" entries therefore overstates token usage by
~2.12x.
- Raw assistant entries with a
usageobject: 2,377 - Distinct
message.id: 1,237 - Distinct
requestId: 1,237 - Distinct
uuid: 2,377
This is reproducible across every session transcript examined (5 sessions, 4 projects). It makes
local usage accounting unreliable unless callers know to deduplicate, and it may affect any
built-in tooling that reads these files. All figures in this report are post-deduplication.
---
Note
Paths, project names and session IDs have been redacted. Full unredacted transcripts and the
analysis scripts used to produce these figures are available on request.
What Should Happen?
I explained everything in "What's Wrong?"
Error Messages/Logs
Steps to Reproduce
I explained everything in "What's Wrong?"
Claude Model
None
Is this a regression?
Yes, this worked in a previous version
Last Working Version
_No response_
Claude Code Version
2.1.247
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Terminal.app (macOS)
Additional Information
_No response_