BerriAI/litellm · error · ValueError
Unexpected key {key!r}; expected 'tool_calls' or 'function_c
Error message
Unexpected key {key!r}; expected 'tool_calls' or 'function_call' What it means
Internal invariant violation: _count_function_call_tokens only handles the keys 'tool_calls' and 'function_call', and it was invoked with a different key. User code cannot normally reach this from public APIs - it indicates a LiteLLM internal dispatch bug or a monkey-patched/vendored copy of the helper.
Source
Thrown at litellm/litellm_core_utils/token_counter.py:431
`function_call` dict. Only the `arguments` string is counted (matching the
existing tool_calls behavior); names are accounted for elsewhere via the
tool/function definitions and `tool_choice`.
"""
if key == "tool_calls":
if not isinstance(value, list):
raise ValueError(f"Unsupported type {type(value)} for key tool_calls in message {message}")
total = 0
for tool_call in value:
if "function" not in tool_call:
raise ValueError(f"Unsupported tool call {tool_call} must contain a function key")
function_arguments = tool_call["function"].get("arguments", "")
total += count_function(str(function_arguments))
return total
if key == "function_call":
if not isinstance(value, Mapping):
raise ValueError(f"Unsupported type {type(value)} for key function_call in message {message}")
return count_function(str(value.get("arguments", "")))
raise ValueError(f"Unexpected key {key!r}; expected 'tool_calls' or 'function_call'")
def _count_messages(
params: _MessageCountParams,
messages: list[AllMessageValues],
use_default_image_token_count: bool,
default_token_count: int | None,
) -> int:
"""
Count the number of tokens in a list of messages.
Args:
params (_MessageCountParams): The parameters for counting tokens.
messages (List[AllMessageValues]): The list of messages to count tokens in.
use_default_image_token_count (bool): When True, will NOT make a GET request to the image URL and instead return the default image dimensions.
default_token_count (Optional[int]): The default number of tokens to return for a message block, if an error occurs.
"""
num_tokens = 0View on GitHub (pinned to 6c2dcb801b)
Solutions
- If calling the private helper directly, pass only 'tool_calls' or 'function_call'.
- Reinstall litellm cleanly (pip install --force-reinstall litellm) to remove mixed/stale copies.
- If it fires from an unmodified install, report upstream with the full traceback.
Defensive patterns
Strategy: try-catch
Try / catch
try:
n = litellm.token_counter(model=m, messages=msgs)
except ValueError as e:
if "Unexpected key" in str(e):
report_bug_with_traceback(e) # internal invariant - not caller-fixable
raise Prevention
- Do not import or call litellm private (_-prefixed) helpers directly.
- Keep a single, clean litellm install per environment to avoid version mixing.
When it happens
Trigger: A modified or partially upgraded litellm install where the dispatch passes a different key; calling the private helper directly with e.g. key='tools'.
Common situations: Editing litellm internals or vendoring parts of token_counter.py; mixed/stale installations after a partial upgrade (stale .pyc, multiple site-packages copies).
Related errors
- Failed to parse Braintrust API response: {str(e)}
- Unexpected responses stream payload
- Stream completed response is invalid
- text and messages cannot both be set
- tools or tool_choice cannot be set if using text
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/f573ac46f5351da0.
Report an issue: GitHub.