diff --git a/litellm/responses/litellm_completion_transformation/transformation.py b/litellm/responses/litellm_completion_transformation/transformation.py index 4acdf4c719f..6db8f75fc11 100644 --- a/litellm/responses/litellm_completion_transformation/transformation.py +++ b/litellm/responses/litellm_completion_transformation/transformation.py @@ -1086,11 +1086,11 @@ class LiteLLMCompletionResponsesConfig: } ) elif part_type in ("input_file", "file"): - normalized_blocks.append( - LiteLLMCompletionResponsesConfig._transform_input_file_item_to_file_item( - part - ) + file_item = LiteLLMCompletionResponsesConfig._transform_input_file_item_to_file_item( + part ) + if file_item.get("file"): + normalized_blocks.append(file_item) # Prefer structured blocks if we have any non-text part # (images or files); otherwise return a string. diff --git a/tests/test_litellm/responses/litellm_completion_transformation/test_function_call_output_normalization.py b/tests/test_litellm/responses/litellm_completion_transformation/test_function_call_output_normalization.py index b2904960253..d51ead9cf5a 100644 --- a/tests/test_litellm/responses/litellm_completion_transformation/test_function_call_output_normalization.py +++ b/tests/test_litellm/responses/litellm_completion_transformation/test_function_call_output_normalization.py @@ -107,3 +107,24 @@ def test_function_call_output_input_file_with_file_id_is_preserved(): file_blocks = [b for b in content if b.get("type") == "file"] assert len(file_blocks) == 1 assert file_blocks[0]["file"]["file_id"] == "file-abc123" + + +def test_function_call_output_input_file_without_data_is_skipped(): + """An input_file part with no file_id, file_url, or file_data carries no + payload — appending it as ``{"type": "file", "file": {}}`` would activate + the structured-content path and emit a hollow block that downstream + adapters (Gemini, Bedrock) reject or silently ignore. Skip it instead.""" + out = LiteLLMCompletionResponsesConfig._transform_responses_api_tool_call_output_to_chat_completion_message( + tool_call_output={ + "type": "function_call_output", + "call_id": "call_empty_file", + "output": [ + {"type": "input_text", "text": "Just text here."}, + {"type": "input_file", "filename": "missing.pdf"}, + ], + } + ) + + assert len(out) == 1 + # No usable file payload -> fall back to the plain-string text path. + assert out[0]["content"] == "Just text here."