OpenHands / OpenHands/software-agent-sdk
AttributeError: 'PromptTokensDetailsWrapper' object has no attribute 'cache_creation_tokens' in Telemetry._cache_buckets
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 1.1k
- Forks
- 542
- Avg merge
- 1d 19h
- Merged PRs (30d)
- 137
Description
Summary
Telemetry._cache_buckets raises 'PromptTokensDetailsWrapper' object has no attribute 'cache_creation_tokens' on LLM responses that report cache reads but no cache creation tokens. This crashes token/cost accounting (and the LLM call) instead of degrading gracefully to cache_write = 0.
Root cause
In openhands/sdk/llm/utils/telemetry.py, _cache_buckets checks for cache-creation tokens like this:
cache_write = (
details.cache_creation_tokens
if "cache_creation_tokens" in details.model_fields_set
else 0
)
details is a litellm PromptTokensDetailsWrapper. The membership check "cache_creation_tokens" in details.model_fields_set is not a reliable presence test:
- The wrapper's
__init__doesdel self.cache_creation_tokenswhenever the value isNone(litellmtypes/utils.py), physically removing the attribute from__dict__. - The field name can still be present in
model_fields_setafter the attribute is deleted — either because it was passed explicitly asNone, or (on newer litellm) because the wrapper's__setattr__mirrors writes betweencache_write_tokensandcache_creation_tokens, stamping both names intomodel_fields_seteven when one is subsequentlydel'd.
So the if branch is taken, details.cache_creation_tokens is accessed, and the attribute is gone → AttributeError.
This is hit by any backend response whose prompt_tokens_details carries cached_tokens (cache read) but no cache-creation count — a very common case (OpenAI prompt caching, DeepSeek, Anthropic cache reads, etc.), and especially reproducible with newer litellm versions (e.g. 1.101.0).
Reproduction
In Agent Canvas (LLM profile/model configuration):
- Duplicate the
glm-5.2model. - Change the duplicated
glm-5.2to point tominimax-m3. - Save.
- Notice the error:
'PromptTokensDetailsWrapper' object has no attribute 'cache_creation_tokens'.
Programmatic reproduction:
from litellm.types.utils import Usage, PromptTokensDetailsWrapper
from openhands.sdk.llm.utils.telemetry import Telemetry
details = PromptTokensDetailsWrapper(cached_tokens=25, cache_creation_tokens=None)
usage = Usage(prompt_tokens=100, completion_tokens=5)
usage.prompt_tokens_details = details
print("in fields_set:", "cache_creation_tokens" in details.model_fields_set) # True
print("hasattr:", hasattr(details, "cache_creation_tokens")) # False
Telemetry._cache_buckets(usage) # raises AttributeError
Fix
Use getattr with a default instead of trusting model_fields_set:
cache_write = getattr(details, "cache_creation_tokens", None)
return int(details.cached_tokens or 0), int(cache_write or 0)
getattr(..., None) returns None when the attribute was deleted, and int(cache_write or 0) normalizes None/0 → 0. This is robust across litellm versions and keeps the Anthropic/OpenAI mirror semantics intact (the wrapper already keeps cache_creation_tokens and cache_write_tokens in sync).
A PR with the fix and a regression test is forthcoming.
This issue was created by an AI agent (OpenHands) on behalf of @juanmichelini.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in openhands/sdk/llm/utils/telemetry.py at Telemetry._cache_buckets and reproduce the failure with the PromptTokensDetailsWrapper example in the issue. Verify that responses with cache reads but no cache-creation attribute produce cache_write = 0 without raising, and add a regression test for this case.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- backend, observability
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100