{"record":{"id":"1df4a5d8aacebe61","repo":"BerriAI/litellm","slug":"missing-required-fields-in-content-type-block","errorCode":null,"errorMessage":"Missing required fields in {content_type} block: {', '.join(missing)}","messagePattern":"Missing required fields in (.+?) block: (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/litellm_core_utils/token_counter.py","lineNumber":631,"sourceCode":"\n    Returns the corresponding TypedDict class if recognized, otherwise raises.\n    \"\"\"\n    content_type: Final = content.get(\"type\")\n    if not content_type:\n        raise ValueError(\"Anthropic content missing required field: 'type'\")\n\n    mapping: Final = {\n        \"tool_use\": AnthropicMessagesToolUseParam,\n        \"tool_result\": AnthropicMessagesToolResultParam,\n    }\n\n    expected_cls: Final = mapping.get(content_type)\n    if expected_cls is None:\n        raise ValueError(f\"Unknown Anthropic content type: '{content_type}'\")\n\n    missing: Final = [k for k in getattr(expected_cls, \"__required_keys__\", set()) if k not in content]\n    if missing:\n        raise ValueError(f\"Missing required fields in {content_type} block: {', '.join(missing)}\")\n\n    return expected_cls\n\n\ndef _count_anthropic_content(\n    content: Mapping[str, Any],\n    count_function: TokenCounterFunction,\n    use_default_image_token_count: bool,\n    default_token_count: int | None,\n) -> int:\n    \"\"\"\n    Count tokens in Anthropic-specific content blocks (tool_use, tool_result, etc.).\n\n    Uses TypedDict definitions from litellm.types.llms.anthropic to determine\n    what fields to count and how to handle nested structures.\n\n    Dynamically infers which fields to count based on the TypedDict definition,\n    avoiding hardcoded field names.","sourceCodeStart":613,"sourceCodeEnd":649,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/litellm_core_utils/token_counter.py#L613-L649","documentation":"The Anthropic content block's 'type' was recognized (tool_use or tool_result), but the block is missing one or more fields the TypedDict marks required (tool_use needs id/name/input; tool_result needs tool_use_id/content). The missing field names are listed in the message.","triggerScenarios":"A tool_result block with content but no tool_use_id (common when echoing results); a tool_use block missing 'input'; blocks trimmed for storage and not restored before replay.","commonSituations":"Agent loops returning tool results and forgetting tool_use_id; persisting pared-down blocks then reusing them for token accounting; schema drift after Anthropic changed required fields.","solutions":["Add the listed missing fields - cross-check the block against Anthropic's docs for its type.","When generating tool_result messages, always carry the id from the originating tool_use block."],"exampleFix":"# before\nresult = {\"type\": \"tool_result\", \"content\": \"22C\"}\n\n# after\nresult = {\"type\": \"tool_result\", \"tool_use_id\": tool_use_id, \"content\": \"22C\"}","handlingStrategy":"validation","validationCode":"REQUIRED = {\"tool_use\": {\"id\", \"name\", \"input\"}, \"tool_result\": {\"tool_use_id\", \"content\"}}\nmissing = REQUIRED[block[\"type\"]] - block.keys()\nif missing:\n    raise ValueError(\"missing \" + str(missing))","typeGuard":"def is_complete_tool_block(block: dict) -> bool:\n    req = {\"tool_use\": {\"id\", \"name\", \"input\"}, \"tool_result\": {\"tool_use_id\", \"content\"}}\n    t = block.get(\"type\")\n    return t in req and req[t] <= block.keys()","tryCatchPattern":null,"preventionTips":["When echoing tool results, copy tool_use_id from the originating tool_use block.","Validate against Anthropic's published schema before persisting tool blocks."],"tags":["token-counter","anthropic","validation","missing-field"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}