{"record":{"id":"f573ac46f5351da0","repo":"BerriAI/litellm","slug":"unexpected-key-key-r-expected-tool-calls-or","errorCode":null,"errorMessage":"Unexpected key {key!r}; expected 'tool_calls' or 'function_call'","messagePattern":"Unexpected key (.+?); expected 'tool_calls' or 'function_call'","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/token_counter.py","lineNumber":431,"sourceCode":"    `function_call` dict. Only the `arguments` string is counted (matching the\n    existing tool_calls behavior); names are accounted for elsewhere via the\n    tool/function definitions and `tool_choice`.\n    \"\"\"\n    if key == \"tool_calls\":\n        if not isinstance(value, list):\n            raise ValueError(f\"Unsupported type {type(value)} for key tool_calls in message {message}\")\n        total = 0\n        for tool_call in value:\n            if \"function\" not in tool_call:\n                raise ValueError(f\"Unsupported tool call {tool_call} must contain a function key\")\n            function_arguments = tool_call[\"function\"].get(\"arguments\", \"\")\n            total += count_function(str(function_arguments))\n        return total\n    if key == \"function_call\":\n        if not isinstance(value, Mapping):\n            raise ValueError(f\"Unsupported type {type(value)} for key function_call in message {message}\")\n        return count_function(str(value.get(\"arguments\", \"\")))\n    raise ValueError(f\"Unexpected key {key!r}; expected 'tool_calls' or 'function_call'\")\n\n\ndef _count_messages(\n    params: _MessageCountParams,\n    messages: list[AllMessageValues],\n    use_default_image_token_count: bool,\n    default_token_count: int | None,\n) -> int:\n    \"\"\"\n    Count the number of tokens in a list of messages.\n\n    Args:\n        params (_MessageCountParams): The parameters for counting tokens.\n        messages (List[AllMessageValues]): The list of messages to count tokens in.\n        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.\n        default_token_count (Optional[int]): The default number of tokens to return for a message block, if an error occurs.\n    \"\"\"\n    num_tokens = 0","sourceCodeStart":413,"sourceCodeEnd":449,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/token_counter.py#L413-L449","documentation":"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.","triggerScenarios":"A modified or partially upgraded litellm install where the dispatch passes a different key; calling the private helper directly with e.g. key='tools'.","commonSituations":"Editing litellm internals or vendoring parts of token_counter.py; mixed/stale installations after a partial upgrade (stale .pyc, multiple site-packages copies).","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."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    n = litellm.token_counter(model=m, messages=msgs)\nexcept ValueError as e:\n    if \"Unexpected key\" in str(e):\n        report_bug_with_traceback(e)  # internal invariant - not caller-fixable\n    raise","preventionTips":["Do not import or call litellm private (_-prefixed) helpers directly.","Keep a single, clean litellm install per environment to avoid version mixing."],"tags":["token-counter","internal","invariant"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}