[BUG] JSONL logs record partial output_tokens from message_start events instead of final totals

Resolved 💬 3 comments Opened Feb 3, 2026 by jsnider3 Closed Feb 3, 2026

Description

The session JSONL logs in ~/.claude/projects/ record output_tokens values from early streaming events (message_start) rather than the final usage totals from message_delta. This causes significant undercounting of output tokens.

Evidence

Analyzing today's JSONL logs:

  • Recorded sum of output_tokens: ~9,600 tokens
  • Estimated actual output (based on response content): ~555,000 tokens
  • Undercounting factor: ~60x

Key indicators that these are partial snapshots:

  1. Every entry has stop_reason: null (indicating incomplete responses)
  2. Maximum output_tokens on any single entry: 29 (impossibly low for actual responses)
  3. The values match what would be expected from message_start events before streaming completes

Sample usage object from JSONL

{
    "input_tokens": 3,
    "cache_creation_input_tokens": 10548,
    "cache_read_input_tokens": 15414,
    "output_tokens": 9,
    "stop_reason": null
}

Impact

  • Cost estimation tools are inaccurate: Third-party tools like ccusage that parse these logs to estimate API costs significantly underreport output token usage and costs
  • No way to get accurate usage data: Users have no reliable method to track their actual output token consumption
  • Input-side metrics appear correct: cache_creation_input_tokens and cache_read_input_tokens are accurate since they're known at message start

Expected Behavior

The JSONL logs should capture the final output_tokens value from the message_delta event at the end of streaming, not the partial count from message_start.

Environment

  • Claude Code version: Latest (as of 2026-02-02)
  • OS: Linux (WSL2)
  • Model: claude-opus-4-5-20251101

Related Issues

  • #20660 - Reports output_tokens: 2 with stop_reason: null (closed as duplicate of hang issues, but the token logging aspect wasn't addressed)
  • #13326 - Reports sidechain agents with output_tokens: 1 and stop_reason: null

View original on GitHub ↗

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