Skip to content

fix: guard null token usage fields in OpenAI converter#575

Merged
marandaneto merged 3 commits into
PostHog:mainfrom
michael-ciridae:fix/null-token-usage-fields
May 21, 2026
Merged

fix: guard null token usage fields in OpenAI converter#575
marandaneto merged 3 commits into
PostHog:mainfrom
michael-ciridae:fix/null-token-usage-fields

Conversation

@michael-ciridae
Copy link
Copy Markdown
Contributor

Problem

extract_openai_usage_from_response crashes with:

TypeError: '>' not supported between instances of 'NoneType' and 'int'

when the OpenAI API response includes prompt_tokens_details.cached_tokens = null or completion_tokens_details.reasoning_tokens = null.

The hasattr() checks pass because the attributes exist on the response object — they're just None. The subsequent > 0 comparisons then fail.

This is common with OpenAI-compatible proxies/gateways that include the token detail objects but set individual fields to null when not applicable (e.g. no caching, no reasoning tokens for a given model).

Fix

  • Add is not None guards before > 0 comparisons in extract_openai_usage_from_response
  • Add is not None guards before assigning to the usage dict in both streaming paths (chat completions and responses API)

Impact

Without this fix, any chat.completions.create() or .parse() call that returns null token detail fields crashes the PostHog wrapper, which propagates up and kills the caller's request — even though the LLM response itself was valid.

Fixes #574

@michael-ciridae michael-ciridae requested a review from a team as a code owner May 14, 2026 13:30
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 14, 2026

Comments Outside Diff (1)

  1. posthog/ai/openai/openai_converter.py, line 403-428 (link)

    P1 Unguarded null for primary token counts

    The same hasattr-passes-but-value-is-null pattern affects the primary count reads at lines 404, 406, 418, and 420. A proxy returning null for those fields overwrites the initial 0 defaults and produces a TokenUsage with None counts — a different crash with the same root cause. Adding or 0 fallbacks at each of those reads would close this gap.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: posthog/ai/openai/openai_converter.py
    Line: 403-428
    
    Comment:
    **Unguarded null for primary token counts**
    
    The same `hasattr`-passes-but-value-is-null pattern affects the primary count reads at lines 404, 406, 418, and 420. A proxy returning `null` for those fields overwrites the initial `0` defaults and produces a `TokenUsage` with `None` counts — a different crash with the same root cause. Adding `or 0` fallbacks at each of those reads would close this gap.
    
    How can I resolve this? If you propose a fix, please make it concise.
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
posthog/ai/openai/openai_converter.py:403-428
**Unguarded null for primary token counts**

The same `hasattr`-passes-but-value-is-null pattern affects the primary count reads at lines 404, 406, 418, and 420. A proxy returning `null` for those fields overwrites the initial `0` defaults and produces a `TokenUsage` with `None` counts — a different crash with the same root cause. Adding `or 0` fallbacks at each of those reads would close this gap.

### Issue 2 of 2
posthog/ai/openai/openai_converter.py:435-501
**No tests for the `None` token-detail fields scenario**

This PR fixes a real crash but adds no test coverage for the triggering condition (`prompt_tokens_details.cached_tokens = None`, `completion_tokens_details.reasoning_tokens = None`). Without a regression test, a future refactor could silently re-introduce the bug. Given the preference for parameterised tests, a single parameterised test covering `(None, None)`, `(0, 0)`, and `(15, 5)` for `(cached_tokens, reasoning_tokens)` in both the streaming and non-streaming paths would prevent this from recurring.

Reviews (1): Last reviewed commit: "fix: guard null token usage fields in Op..." | Re-trigger Greptile

Comment thread posthog/ai/openai/openai_converter.py
@marandaneto marandaneto requested a review from a team May 14, 2026 13:38
@gregciridae
Copy link
Copy Markdown

Just ran into this issue again, thanks Michael :)

@marandaneto
Copy link
Copy Markdown
Member

@PostHog/team-llm-analytics is this safe to go?

@marandaneto
Copy link
Copy Markdown
Member

i pushed the changeset entry and a test, will release it

michael-ciridae and others added 3 commits May 21, 2026 15:11
`extract_openai_usage_from_response` crashes with TypeError when the
OpenAI API response includes null values for `cached_tokens` or
`reasoning_tokens` in token detail objects. The `hasattr()` checks pass
because the attributes exist — they're just None.

This is common with OpenAI-compatible proxies/gateways that include the
detail objects but set individual fields to null when not applicable.

Add None checks before `> 0` comparisons and before assigning to the
usage dict in streaming paths.

Fixes PostHog#574
@marandaneto marandaneto force-pushed the fix/null-token-usage-fields branch from 0c74495 to f33faf5 Compare May 21, 2026 13:12
@marandaneto
Copy link
Copy Markdown
Member

force pushed commits so they are all signed, its a blocker for merging

@marandaneto marandaneto merged commit 1574b1b into PostHog:main May 21, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TypeError in OpenAI converter when token usage detail fields are null

3 participants