diff --git a/litellm/llms/anthropic/chat/transformation.py b/litellm/llms/anthropic/chat/transformation.py index 879be22d94f..99979e29a23 100644 --- a/litellm/llms/anthropic/chat/transformation.py +++ b/litellm/llms/anthropic/chat/transformation.py @@ -195,7 +195,7 @@ def _tool_call_ids_failing( def _non_string_roles(messages: Sequence[object]) -> Iterator[tuple[str, object]]: roles: Final = ((index, message_field(message, "role")) for index, message in enumerate(messages)) - return ((f"messages[{index}].role", role) for index, role in roles if is_present_non_string(role)) + return ((f"messages[{index}].role", role) for index, role in roles if role and is_present_non_string(role)) def _assistant_tool_call_ids_failing( diff --git a/tests/unit/llms/anthropic/chat/test_anthropic_chat_transformation.py b/tests/unit/llms/anthropic/chat/test_anthropic_chat_transformation.py index debe537fb7f..0a9856b72f3 100644 --- a/tests/unit/llms/anthropic/chat/test_anthropic_chat_transformation.py +++ b/tests/unit/llms/anthropic/chat/test_anthropic_chat_transformation.py @@ -10169,6 +10169,19 @@ def test_chat_transform_request_never_blames_a_numeric_assistant_tool_call_id_fo assert raised.value.message.startswith("'str' object has no attribute 'get'") +@pytest.mark.parametrize("empty_role", [[], 0, False]) +def test_chat_transform_request_never_blames_an_empty_role_for_another_failure(local_model_cost_map, empty_role): + list_part_type_after_an_empty_role: Final = [ + _ASK, + {"role": empty_role, "content": "ok"}, + {"role": "user", "content": [{"type": ["text"], "text": "again"}]}, + {"role": "system", "content": "Be terse."}, + ] + + with pytest.raises(TypeError): + _chat_request(AnthropicConfig(), FLAGGED_CLAUDE, list_part_type_after_an_empty_role) + + def test_chat_transform_request_names_no_field_for_a_failure_outside_roles_and_tool_call_ids(local_model_cost_map): list_part_type: Final = [ _ASK,