`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
Problem
extract_openai_usage_from_responsecrashes with:when the OpenAI API response includes
prompt_tokens_details.cached_tokens = nullorcompletion_tokens_details.reasoning_tokens = null.The
hasattr()checks pass because the attributes exist on the response object — they're justNone. The subsequent> 0comparisons 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
is not Noneguards before> 0comparisons inextract_openai_usage_from_responseis not Noneguards 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