From def910b08692f515cb65c22845d2dc6d204ae254 Mon Sep 17 00:00:00 2001 From: Neha Prasad Date: Thu, 5 Feb 2026 13:02:34 +0530 Subject: [PATCH] fix: Sanitize empty text content blocks for databricks provider (#20384) * fix(databricks): sanitize empty text content blocks for Anthropic Messages API * test(databricks): add tests for empty content block sanitization --- .../llms/databricks/chat/transformation.py | 33 ++++++++++++++ .../test_databricks_chat_transformation.py | 43 +++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/litellm/llms/databricks/chat/transformation.py b/litellm/llms/databricks/chat/transformation.py index e9ae94307d..2699b0618b 100644 --- a/litellm/llms/databricks/chat/transformation.py +++ b/litellm/llms/databricks/chat/transformation.py @@ -60,6 +60,38 @@ from ...anthropic.chat.transformation import AnthropicConfig from ...openai_like.chat.transformation import OpenAILikeChatConfig from ..common_utils import DatabricksBase, DatabricksException +def _sanitize_empty_content(message_dict: dict) -> None: + """ + Remove or filter content so empty text blocks are not sent. + Databricks Model Serving uses Anthropic Messages API spec and rejects empty text blocks. + """ + content = message_dict.get("content") + if content is None: + message_dict.pop("content", None) + return + if isinstance(content, str): + if not content.strip(): + message_dict.pop("content") + return + if isinstance(content, list): + if not content: + message_dict.pop("content") + return + filtered = [ + block + for block in content + if not ( + isinstance(block, dict) + and block.get("type") == "text" + and not (block.get("text") or "").strip() + ) + ] + if not filtered: + message_dict.pop("content") + else: + message_dict["content"] = filtered + + if TYPE_CHECKING: from litellm.litellm_core_utils.litellm_logging import Logging as _LiteLLMLoggingObj @@ -350,6 +382,7 @@ class DatabricksConfig(DatabricksBase, OpenAILikeChatConfig, AnthropicConfig): # Move message-level cache_control into a content block when content is a string. if "cache_control" in _message and isinstance(_message.get("content"), str): _message = self._move_cache_control_into_string_content_block(_message) + _sanitize_empty_content(_message) new_messages.append(_message) if is_async: diff --git a/tests/test_litellm/llms/databricks/chat/test_databricks_chat_transformation.py b/tests/test_litellm/llms/databricks/chat/test_databricks_chat_transformation.py index f437b8405f..f9b5b5fe29 100644 --- a/tests/test_litellm/llms/databricks/chat/test_databricks_chat_transformation.py +++ b/tests/test_litellm/llms/databricks/chat/test_databricks_chat_transformation.py @@ -13,6 +13,7 @@ from unittest.mock import MagicMock, patch from litellm.llms.databricks.chat.transformation import ( DatabricksChatResponseIterator, DatabricksConfig, + _sanitize_empty_content, ) @@ -215,3 +216,45 @@ def test_chunk_parser_with_citation(): "end_char_index": 50, } } + + +def test_sanitize_empty_content_pops_none(): + message = {"role": "user", "content": None} + _sanitize_empty_content(message) + assert "content" not in message + + +def test_sanitize_empty_content_pops_empty_string(): + message = {"role": "user", "content": ""} + _sanitize_empty_content(message) + assert "content" not in message + + +def test_sanitize_empty_content_pops_single_empty_text_block(): + message = {"role": "user", "content": [{"type": "text", "text": ""}]} + _sanitize_empty_content(message) + assert "content" not in message + + +def test_sanitize_empty_content_filters_empty_blocks_keeps_non_empty(): + message = { + "role": "user", + "content": [ + {"type": "text", "text": ""}, + {"type": "text", "text": "Hello"}, + {"type": "text", "text": " "}, + ], + } + _sanitize_empty_content(message) + assert message["content"] == [{"type": "text", "text": "Hello"}] + + +def test_transform_messages_sanitizes_empty_content(): + config = DatabricksConfig() + messages = [ + {"role": "user", "content": [{"type": "text", "text": ""}]}, + {"role": "user", "content": "Hi"}, + ] + result = config._transform_messages(messages=messages, model="databricks-claude", is_async=False) + assert "content" not in result[0] + assert result[1]["content"] == "Hi"