feat(langchain): report cached and reasoning token usage in Langchain/Langgraph#6800
Conversation
The Langchain and Langgraph integrations only recorded input, output, and total token counts, dropping cached input tokens and reasoning output tokens even though SPANDATA defines both and the OpenAI, OpenAI Agents, and Google GenAI integrations already report them. Extract cache_read/cached_tokens and reasoning/reasoning_tokens from both the LangChain usage_metadata detail shape and OpenAI-style details dicts, and set gen_ai.usage.input_tokens.cached and gen_ai.usage.output_tokens.reasoning on spans in both integrations. Fixes getsentryGH-6799
| cached_tokens = _get_value(input_details, "cache_read") or _get_value( | ||
| input_details, "cached_tokens" | ||
| ) |
There was a problem hiding this comment.
Bug: The use of the or operator incorrectly handles legitimate 0 values for token counts, causing them to be evaluated as None and dropped from span data.
Severity: MEDIUM
Suggested Fix
Refactor the logic to avoid using the or operator for fallback when 0 is a valid value. Instead, explicitly check if the first value is None before attempting to retrieve the second value. This ensures that a 0 from the primary key is preserved.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: sentry_sdk/integrations/langchain.py#L752-L754
Potential issue: In the `_extract_tokens` function, the use of the `or` operator to
select between two potential keys for token counts (e.g., `cache_read` or
`cached_tokens`) leads to incorrect behavior when a valid token count is `0`. Because
`0` is a falsy value in Python, the expression proceeds to evaluate the right-hand side.
If the alternative key does not exist, the result becomes `None`. This causes legitimate
zero-token counts for cached or reasoning tokens to be silently dropped instead of being
reported in span data. While this has minimal impact on cost calculations, it is a
correctness issue that prevents accurate reporting of API responses.
Also affects:
sentry_sdk/integrations/langchain.py:761~763sentry_sdk/integrations/langchain.py:737~738sentry_sdk/integrations/langchain.py:742~743
Did we get this right? 👍 / 👎 to inform future reviews.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Want reviews to match your repository better? Bugbot Learning can learn team-specific rules from PR activity. A team admin can enable Learning in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit cb26c51. Configure here.
| cached_tokens += int(input_details.get("cached_tokens") or 0) | ||
|
|
||
| output_details = token_usage.get("completion_tokens_details") or {} | ||
| reasoning_tokens += int(output_details.get("reasoning_tokens") or 0) |
There was a problem hiding this comment.
Langgraph misses LangChain token shapes
Medium Severity
_set_usage_data only reads cached_tokens and reasoning_tokens from OpenAI-style prompt_tokens_details / completion_tokens_details. It never checks LangChain’s input_token_details / output_token_details or the cache_read / reasoning keys that _extract_tokens handles in the Langchain integration, so cached and reasoning usage can be omitted on Langgraph spans.
Reviewed by Cursor Bugbot for commit cb26c51. Configure here.


Description
The Langchain and Langgraph integrations only recorded input/output/total token counts, dropping cached input tokens and reasoning output tokens — even though
SPANDATAdefines both and the OpenAI, OpenAI Agents, and Google GenAI integrations already report them. This makes cache-discount and reasoning-token cost calculations inaccurate for Langchain/Langgraph apps.This extracts
cache_read/cached_tokensandreasoning/reasoning_tokensfrom both the LangChainusage_metadatadetail shape (input_token_details/output_token_details) and OpenAI-style details dicts (prompt_tokens_details/completion_tokens_details), and setsgen_ai.usage.input_tokens.cached/gen_ai.usage.output_tokens.reasoningin both integrations. Tests cover both detail shapes, span data emission, and the Langgraph accumulation loop (all three fail on master and pass with this change); ruff clean.Issues