{"record":{"id":"cc379b011ade9351","repo":"BerriAI/litellm","slug":"message-i-must-have-a-content-field-cc379b","errorCode":null,"errorMessage":"Message {i} must have a 'content' field","messagePattern":"Message (.+?) must have a 'content' field","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/bedrock/count_tokens/transformation.py","lineNumber":277,"sourceCode":"\n        if input_type == \"converse\":\n            # Validate Converse format (messages-based)\n            messages: Final = request_data.get(\"messages\", [])\n            if not messages:\n                raise ValueError(\"messages parameter is required for Converse input\")\n\n            if not isinstance(messages, list):\n                raise ValueError(\"messages must be a list\")\n\n            for i, message in enumerate(messages):\n                if not isinstance(message, dict):\n                    raise ValueError(f\"Message {i} must be a dictionary\")\n\n                if \"role\" not in message:\n                    raise ValueError(f\"Message {i} must have a 'role' field\")\n\n                if \"content\" not in message:\n                    raise ValueError(f\"Message {i} must have a 'content' field\")\n        else:\n            # For InvokeModel format, we need at least some content to count tokens\n            # The content structure varies by model, so we do minimal validation\n            if len(request_data) <= 1:  # Only has 'model' field\n                raise ValueError(\"Request must contain content to count tokens\")\n","sourceCodeStart":259,"sourceCodeEnd":283,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/bedrock/count_tokens/transformation.py#L259-L283","documentation":"Converse-format validation requiring each message dict to contain a 'content' key. A message with only a role (e.g. {'role': 'user'}) fails here; the index i identifies which message.","triggerScenarios":"Placeholder/empty turns like {'role': 'assistant'} used as conversation delimiters, or code that builds messages progressively and sends one before content is attached.","commonSituations":"Template-driven prompt builders that append role stubs first, or trimming logic that drops content while keeping the role shell.","solutions":["Give every message a content value, even if minimal: {'role': 'user', 'content': [{'text': ''}]}","Remove role-only stub messages before the call"],"exampleFix":"# before\nmessages=[{'role': 'user'}, {'role': 'assistant', 'content': [...]}]\n\n# after\nmessages=[{'role': 'user', 'content': [{'text': 'continue'}]}, {'role': 'assistant', 'content': [...]}]","handlingStrategy":"validation","validationCode":"for i, m in enumerate(req[\"messages\"]):\n    if \"content\" not in m:\n        raise ValueError(f\"Message {i} must have a 'content' field\")","typeGuard":"def has_content(m: dict) -> bool:\n    return isinstance(m, dict) and \"content\" in m and m[\"content\"] is not None","tryCatchPattern":null,"preventionTips":["Drop role-only stub messages during conversation trimming","Default missing content to [{'text': ''}] if the turn must be preserved"],"tags":["bedrock","count-tokens","validation"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}