[BUG] sum of output_tokens from assistant messages returned by claude-agent-sdk query() doesn't equal output_tokens of the "result" message

Resolved 💬 2 comments Opened Mar 26, 2026 by smnh Closed Apr 26, 2026

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?

When iterating over messages generated by the query() method of @anthropic-ai/claude-agent-sdk, I collect token usage data from the message.usage of each assistant message and sum their values. However, the total sum of all output_tokens doesn't equal the value of output_tokens in the final result message.

I'm using @anthropic-ai/claude-agent-sdk version 0.2.84.
Model: claude-opus-4-6, but this happens for other models too.

I've followed the rules described in the https://platform.claude.com/docs/en/agent-sdk/cost-tracking documentation regarding skipping duplicate usages of messages with the same ID.

I discovered that when setting includePartialMessages to true and counting output_tokens from stream_event messages of type message_delta (instead of from assistant messages), I get the correct sum for output_tokens.

I've created a simple Node.js script available in this gist that calls query() with a simple prompt to test token usage and print the results.

Running query() with options.includePartialMessages: false
The sum of output_tokens from assistant messages doesn't equal the value of output_tokens in the final result message.

MESSAGE USAGE BREAKDOWN
==============================================================================
Message ID                     |  Input | Cache Create | Cache Read |   Output
------------------------------------------------------------------------------
msg_01Ea9T1t5eDLV7BZyVjd22bu   |      3 |         2197 |       7233 |       30
msg_01NjzSe7a9fHiBq9nWNKWFLZ   |      3 |         1137 |       9430 |       47
msg_013WH4Ksf9ZWSokidLhnypYq   |      1 |          100 |      10567 |        1
------------------------------------------------------------------------------
Total                          |      7 |         3434 |      27230 |       78
------------------------------------------------------------------------------
type: result                   |      7 |         3434 |      27230 |      275
==============================================================================

TOKEN USAGE COMPARISON
========================================================
Token Type                     |   Computed |     Result
--------------------------------------------------------
✓ Input Tokens                 |          7 |          7
✓ Cache Creation Tokens        |       3434 |       3434
✓ Cache Read Tokens            |      27230 |      27230
✗ Output Tokens                |         78 |        275 (diff: -197)
========================================================
✗ Discrepancies in token counts detected

Running query() with options.includePartialMessages: true
The sum of output_tokens ONLY from stream_event messages with event type message_delta equals the value of output_tokens in the final result message.

Tokens in brackets [] are ignored when computing totals.

MESSAGE USAGE BREAKDOWN
==============================================================================
Message ID                     |  Input | Cache Create | Cache Read |   Output
------------------------------------------------------------------------------
msg_01EdnokfMQShjSdfXjGvHivj   |      3 |         2197 |       7233 |     [24]
type: message_delta            |    [3] |       [2197] |     [7233] |      114
msg_01WN1oaCiJBx7yZTEUwHjENZ   |      3 |         1662 |       8402 |     [53]
type: message_delta            |    [3] |       [1662] |     [8402] |       97
msg_01YHKzFDhysvSK1BLRxenY1M   |      1 |          254 |      10064 |      [7]
type: message_delta            |    [1] |        [254] |    [10064] |       45
------------------------------------------------------------------------------
Total                          |      7 |         4113 |      25699 |      256
------------------------------------------------------------------------------
type: result                   |      7 |         4113 |      25699 |      256
==============================================================================

TOKEN USAGE COMPARISON
========================================================
Token Type                     |   Computed |     Result
--------------------------------------------------------
✓ Input Tokens                 |          7 |          7
✓ Cache Creation Tokens        |       4113 |       4113
✓ Cache Read Tokens            |      25699 |      25699
✓ Output Tokens                |        256 |        256
========================================================
✓ All token counts match!
   ```

### What Should Happen?

When using `query()` with `options.includePartialMessages: false`, the sum of `message.usage.output_tokens` from all unique `assistant` messages (deduplicated by message ID, as documented in the cost tracking guide) should equal the `usage.output_tokens` of the final `result` message.                                                                                                                                                                                                 

This matches the expected behavior for `input_tokens`, `cache_creation_input_tokens`, and `cache_read_input_tokens`, which all sum correctly, only `output_tokens` shows this discrepancy.

### Error Messages/Logs

```shell

Steps to Reproduce

Steps to Reproduce:

  1. Run the provided gist script with includePartialMessages set to false (default in the script).
  2. Observe the MESSAGE USAGE BREAKDOWN table - note the "Total" row showing summed output_tokens from all assistant messages.
  3. Compare this total with the "type: result" row showing the final result message's output_tokens.
  4. Check the TOKEN USAGE COMPARISON section at the bottom.

Expected Result:

  • The "Total" and "type: result" rows should have matching output_tokens values.
  • The script should print ✓ All token counts match!

Actual Result:

  • The output_tokens values don't match.
  • The script prints ✗ Discrepancies in token counts detected

Claude Model

Opus

Is this a regression?

No, this never worked

Last Working Version

_No response_

Claude Code Version

2.1.84

Platform

Anthropic API

Operating System

macOS

Terminal/Shell

Terminal.app (macOS)

Additional Information

_No response_

View original on GitHub ↗

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