Extended thinking generates duplicate .jsonl log entries with identical input tokens, causing ~2-3x token inflation in usage tracking

Resolved 💬 7 comments Opened Mar 31, 2026 by 1719930244 Closed May 13, 2026

Bug Description

When extended thinking is enabled, each API call is logged as 2–5 separate entries in the .jsonl conversation log, all sharing identical cache_read_input_tokens and cache_creation_input_tokens values. This causes the local usage counter to over-count token consumption by approximately , and we suspect the rate-limit usage indicator shown in the UI is also affected (see Open Question below).

Environment

  • Claude Code version: 2.1.77 (auto-updated to 2.1.88 shortly after; not yet verified on 2.1.88)
  • OS: Linux (x64)
  • Models affected: claude-opus-4-6 AND claude-sonnet-4-6 (both confirmed)
  • Trigger: Extended thinking enabled — reproducible via CLAUDE_CODE_EFFORT_LEVEL=max, or any configuration that activates extended thinking (settings.json thinking budget, /model selection, etc.)

Trigger Conditions

The duplication occurs on every API call where extended thinking is active. Turns without thinking produce a single FINAL entry with no duplication.

Per API call, the log contains:

| Entry type | inference_geo | output_tokens | content types | has iterations/speed |
|---|---|---|---|---|
| PRELIM #1 | "not_available" | 0–40 (thinking tokens) | ["thinking"] | ✗ |
| PRELIM #2 (sometimes) | "not_available" | same value as PRELIM #1 | ["text"] or ["tool_use"] | ✗ |
| FINAL | "" | actual response tokens | ["tool_use"] / ["text"] | ✓ |

All entries for the same API call share identical cache_read_input_tokens and cache_creation_input_tokens. In multi-agent sessions with concurrent subagents, duplication reaches up to 7 entries per call.

Steps to Reproduce

  1. Set CLAUDE_CODE_EFFORT_LEVEL=max (or enable extended thinking via any other config)
  2. Start a session in any project directory
  3. Send a few messages that trigger tool use (e.g. ask Claude to read a file)
  4. Inspect ~/.claude/projects/<project>/<session-id>.jsonl
  5. Find consecutive type: "assistant" entries with identical cache_read_input_tokens — the earlier entries will have inference_geo: "not_available" and lack iterations/speed fields

Expected: One log entry per API call; or if streaming intermediaries are logged, only FINAL entry tokens count toward usage
Actual: 2–5 entries per call with identical input token counts logged

Quantified Impact (from session analysis)

Analysis of a full 5-hour window (929 logged assistant entries across 4 sessions, both Opus 4.6 and Sonnet 4.6):

| | Call count | Effective input tokens |
|---|---|---|
| FINAL entries only (actual cost) | 474 | 4,862,690 |
| PRELIM entries (duplication) | 455 | 4,706,607 |
| Total as logged | 929 | 9,569,298 |
| Inflation multiplier | — | 1.97× |

In the worst 20-minute window (multi-agent evaluation session):

| | Call count | Effective input tokens |
|---|---|---|
| FINAL only | 105 | 1,165,909 |
| PRELIM (duplication) | 138 | 1,913,550 |
| Total as logged | 243 | 3,079,459 |
| Inflation multiplier | — | 2.64× |

~49–62% of logged token consumption is phantom duplication.

Evidence from Logs

Single-agent example (same cr=27,874, three entries):

06:15:28  PRELIM  out=34  content=["thinking"]   inference_geo="not_available"  (no iterations/speed)
06:15:29  PRELIM  out=34  content=["text"]        inference_geo="not_available"  (no iterations/speed)
06:15:34  FINAL   out=955 content=["tool_use"]    inference_geo=""               (has iterations/speed)

Multi-agent example (same cr=109,079, 7 entries):

06:13:09  out=8   content=["tool_use"]  inference_geo="not_available"
06:13:09  out=8   content=["tool_use"]  inference_geo="not_available"
06:13:10  out=8   content=["tool_use"]  inference_geo="not_available"
06:13:10  out=8   content=["tool_use"]  inference_geo="not_available"
06:13:11  out=8   content=["tool_use"]  inference_geo="not_available"
06:13:11  out=8   content=["tool_use"]  inference_geo="not_available"
06:13:12  out=606 content=["tool_use"]  inference_geo=""  ← FINAL

Open Question

It is unclear whether Anthropic's server-side rate limiter counts PRELIM entries separately or deduplicates them. The JSONL files are client-side logs. However:

  • A 20-minute session showed ~30% of the 5-hour quota consumed
  • Based on FINAL-only tokens, actual consumption should be ~11%
  • This is consistent with a ~2.64× inflation reaching the rate-limit counter

We'd appreciate clarification on whether the rate-limit accounting is based on individual streaming events (PRELIM + FINAL) or per logical API call (FINAL only).

View original on GitHub ↗

This issue has 7 comments on GitHub. Read the full discussion on GitHub ↗