{"record":{"id":"043ed5109f00c465","repo":"BerriAI/litellm","slug":"error-getting-number-of-tokens-from-content-list","errorCode":null,"errorMessage":"Error getting number of tokens from content list: {e}, default_token_count={default_token_count}","messagePattern":"Error getting number of tokens from content list: (.+?), default_token_count=(.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"litellm/litellm_core_utils/token_counter.py","lineNumber":738,"sourceCode":"                # The full tool definition is counted via the `tools` param, so we\n                # only count the referenced name here. Without this branch,\n                # token_counter raises on tool-search traffic; on the streaming\n                # anthropic_messages path that nulls response_cost and causes the\n                # proxy to drop the SpendLogs row entirely (silent cost undercount).\n                tool_name = str(c.get(\"tool_name\") or \"\")\n                if tool_name:\n                    num_tokens += count_function(tool_name)\n            else:\n                content_type = c.get(\"type\", type(c).__name__) if isinstance(c, dict) else type(c).__name__\n                raise ValueError(\n                    f\"Invalid content item type: {content_type}. \"\n                    f\"Expected str or dict with 'type' field (text, image_url, tool_use, tool_result, thinking, tool_reference).\"\n                )\n        return num_tokens\n    except Exception as e:\n        if default_token_count is not None:\n            return default_token_count\n        raise ValueError(\n            f\"Error getting number of tokens from content list: {e}, default_token_count={default_token_count}\"\n        )\n\n\ndef _format_function_definitions(tools):\n    \"\"\"Formats tool definitions in the format that OpenAI appears to use.\n    Based on https://github.com/forestwanglin/openai-java/blob/main/jtokkit/src/main/java/xyz/felh/openai/jtokkit/utils/TikTokenUtils.java\n    \"\"\"\n    lines: Final = []\n    lines.append(\"namespace functions {\")\n    lines.append(\"\")\n    for tool in tools:\n        if not isinstance(tool, dict):\n            continue\n        function = tool.get(\"function\")\n        if not isinstance(function, dict):\n            # Anthropic tool shape → OpenAI function dict for token counting.\n            params = tool.get(\"input_schema\") or tool.get(\"parameters\") or {}","sourceCodeStart":720,"sourceCodeEnd":756,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/token_counter.py#L720-L756","documentation":"Catch-all for any exception raised while counting a content list: the original error is wrapped with the default_token_count value for context. It usually wraps one of the deeper ValueErrors (invalid image_url, invalid content item type, encoder failure on exotic text). If default_token_count was provided, that value is returned instead of raising.","triggerScenarios":"Any token_counter(messages=[...]) call where a content block fails deeper validation and no default_token_count was given - bad image detail, unknown block type, or an encoder exception on unusual unicode.","commonSituations":"Proxy cost-accounting paths that count arbitrary user traffic; untrusted or multimodal request bodies; token counting right after a provider introduces new content features.","solutions":["Read the wrapped inner error (embedded in the message) and fix that specific block.","Call token_counter with default_token_count=<int> so malformed blocks fall back to an estimate.","Validate and sanitize message content before counting."],"exampleFix":"# before\nn = litellm.token_counter(model=m, messages=msgs)  # raises wrapped error\n\n# after\ntry:\n    n = litellm.token_counter(model=m, messages=msgs)\nexcept ValueError as e:\n    log.warning(\"token count failed, estimating: %s\", e)\n    n = litellm.token_counter(model=m, messages=msgs, default_token_count=4)","handlingStrategy":"fallback","validationCode":"n = litellm.token_counter(model=model, messages=msgs, default_token_count=4)","typeGuard":null,"tryCatchPattern":"try:\n    n = litellm.token_counter(model=m, messages=msgs)\nexcept ValueError as e:\n    log.warning(\"token counting degraded: %s\", e)\n    n = estimate_tokens(msgs)  # len(content)//4 heuristic or retry with default_token_count","preventionTips":["Always pass default_token_count on cost-accounting paths over user traffic.","Validate message content (known block types, valid image urls) before counting.","Read the embedded inner exception - it identifies the exact failing block."],"tags":["token-counter","wrapped-error","fallback","validation"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}