[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:
- Every entry has
stop_reason: null(indicating incomplete responses) - Maximum
output_tokenson any single entry: 29 (impossibly low for actual responses) - The values match what would be expected from
message_startevents 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_tokensandcache_read_input_tokensare 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: 2withstop_reason: null(closed as duplicate of hang issues, but the token logging aspect wasn't addressed) - #13326 - Reports sidechain agents with
output_tokens: 1andstop_reason: null
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗