anthropics / anthropics/claude-code
[BUG] Transcript rows zero every usage counter but keep usage.cache_creation — cache_creation_input_tokens != sum(cache_creation)
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 146k
- Forks
- 23.8k
- PR merge metrics
- PR metrics pending
Description
What's wrong
Some assistant rows in session transcripts (~/.claude/projects/**/*.jsonl) have every top-level usage counter set to 0, while usage.cache_creation still holds the real write. That breaks the invariant documented on the prompt-caching page, under 1-hour cache duration: "the current cache_creation_input_tokens field equals the sum of the values in the cache_creation object."
In most cases another row of the same message (same message.id + requestId) carries the correct, consistent usage. So this looks like a row written with a zeroed usage snapshot, not an API response that disagrees with itself.
Example
Two rows of one message, CC 2.1.237, claude-opus-5, both with content: [text]. Usage fields only:
{"input_tokens": 2, "cache_creation_input_tokens": 977, "cache_read_input_tokens": 316685, "output_tokens": 5175, "cache_creation": {"ephemeral_1h_input_tokens": 977, "ephemeral_5m_input_tokens": 0}}
{"input_tokens": 0, "cache_creation_input_tokens": 0, "cache_read_input_tokens": 0, "output_tokens": 0, "cache_creation": {"ephemeral_1h_input_tokens": 977, "ephemeral_5m_input_tokens": 0}}
How often (one machine, 2026-07-10 → 2026-09-19)
- 540,177 assistant rows carrying
usage.cache_creation, across 153,985 distinct messages - 153 messages have at least one row where
cache_creation_input_tokens != sum(cache_creation.*)- in 136 of them, another row of the same message is consistent
- 17 messages have no consistent row at all. For those, the transcript records a cache write only in the nested object.
- Direction: almost always
cache_creation_input_tokens = 0with a non-zero split. The largest single row is 417,471 tokens reported as 0. - Seen on 20 CC versions from 2.1.205 through 2.1.275, and on
claude-opus-5,claude-opus-4-8,claude-fable-5,claude-fable-5-1. - Stop reasons
end_turnandtool_use. Content typestext,thinking,tool_use. None are API-error rows.
Why it matters
Anything that accounts for cache writes from transcripts reads the top-level field and silently undercounts. That includes cost reports and cache-rebuild analysis. Readers that de-duplicate by message id and keep the first row are affected whenever the zeroed row comes first.
Expected
Every row written for a message carries the same usage, or at least one that satisfies the documented invariant.
Repro (read-only)
For each assistant row with message.usage.cache_creation, compare cache_creation_input_tokens with the sum of the cache_creation values. Then group by (message.id, requestId).
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the read-only scan of assistant rows in ~/.claude/projects/**/*.jsonl, comparing cache_creation_input_tokens with the cache_creation sum and grouping by message.id and requestId. Trace the transcript-writing entry point that produces these rows and check how repeated rows receive usage snapshots. Done means written rows preserve the documented invariant and the repro no longer finds inconsistent usage.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 50/100