BerriAI/litellm · error · ValueError
usage is required, got={usage} of type {type(usage)}
Error message
usage is required, got={usage} of type {type(usage)} What it means
ResponseAPILoggingUtils.get_usage_from_response_obj normalizes the usage field and accepts only a Usage object, an OpenAI Responses-API ResponseAPIUsage object, or a plain dict. Any other type (None that isn't pre-handled, a string, a pydantic model from another library, an arbitrary object) reaches the terminal raise. The error exists to prevent silent zero-usage logging when callers pass malformed usage payloads.
Source
Thrown at litellm/litellm_core_utils/litellm_logging.py:4934
)
usage: Final = response_obj.get("usage", None) or {}
if usage is None or (not isinstance(usage, dict) and not isinstance(usage, Usage)):
return Usage(
prompt_tokens=0,
completion_tokens=0,
total_tokens=0,
)
elif isinstance(usage, Usage):
return usage
elif isinstance(usage, ResponseAPIUsage):
return ResponseAPILoggingUtils._transform_response_api_usage_to_chat_usage(usage)
elif isinstance(usage, dict):
if ResponseAPILoggingUtils._is_response_api_usage(usage):
return ResponseAPILoggingUtils._transform_response_api_usage_to_chat_usage(usage)
return Usage(**usage)
raise ValueError(f"usage is required, got={usage} of type {type(usage)}")
@staticmethod
def get_usage_as_dict(
response_obj: dict | None,
combined_usage_object: Usage | None = None,
) -> dict:
"""
Like get_usage_from_response_obj but returns a plain dict, skipping
the Pydantic Usage construction on the hot path.
"""
_empty: Final[dict] = {"prompt_tokens": 0, "completion_tokens": 0, "total_tokens": 0}
if combined_usage_object is not None:
return combined_usage_object.model_dump()
if not response_obj:
return _empty
_raw: Final = response_obj.get("usage", None)
if _raw is None:
return _emptyView on GitHub (pinned to 6c2dcb801b)
Solutions
- Convert before logging: pass usage as a plain dict (Usage(**d) is constructed for you) or a litellm.Usage instance
- In provider adapters, transform provider-specific usage into Usage/ResponseAPIUsage before the response reaches logging
- In tests, replace MagicMocks for usage with real Usage objects or dicts
Example fix
# before
usage = '{"prompt_tokens": 1}' # str -> ValueError
# after
usage = {"prompt_tokens": 1, "completion_tokens": 2, "total_tokens": 3}
# or
from litellm import Usage
usage = Usage(prompt_tokens=1, completion_tokens=2, total_tokens=3) Defensive patterns
Strategy: type-guard
Validate before calling
from litellm import Usage
def normalize_usage(u):
if isinstance(u, Usage) or isinstance(u, dict):
return u
if u is None:
return {'prompt_tokens': 0, 'completion_tokens': 0, 'total_tokens': 0}
raise TypeError(f'unsupported usage type: {type(u)}') Type guard
from litellm import Usage
def is_supported_usage(u) -> bool:
return isinstance(u, (Usage, dict)) # ResponseAPIUsage also accepted upstream Prevention
- In adapters, convert provider usage objects to litellm.Usage or a dict before logging
- Use real Usage objects in tests, never strings or mocks
- Centralize usage transformation in one helper per provider
When it happens
Trigger: Custom callbacks/handlers (or downstream code overriding response objects) passing usage as something other than Usage/ResponseAPIUsage/dict — e.g. usage=None bypassing the falsy branch because an earlier branch already consumed the empty case, usage as a JSON string, or a provider-specific usage model not yet transformed.
Common situations: Adding new providers whose raw usage objects are forwarded untransformed; mocking responses in tests with usage as a string or MagicMock; adapter code copying usage between response types.
Related errors
- start_time is required, got={start_time} of type {type(start
- end_time is required, got={end_time} of type {type(end_time)
- Model is None and does not exist in passed completion_respon
- usage object and custom_llm_provider must be provided for re
- response must be of type OCRResponse got type={type(response
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/541321fb5591ef01.
Report an issue: GitHub.