From 668df706987eb702ccf4b0f9d3a85bacfbde91f2 Mon Sep 17 00:00:00 2001 From: Jean Carlos NUnez Date: Thu, 2 Apr 2026 01:19:18 -0500 Subject: [PATCH] fix(gemini): handle Gemini Files API URIs in _process_gemini_media without mime type resolution Gemini Files API URIs (https://generativelanguage.googleapis.com/v1beta/files/*) have no file extension and return 403 for unauthenticated requests, causing litellm to crash when trying to sniff the mime type. Add an explicit branch that forwards these URIs as file_data without attempting mime type resolution, since the Files API already knows the type of the uploaded file. Fixes #24907 Co-Authored-By: Claude Sonnet 4.6 --- .../llms/vertex_ai/gemini/transformation.py | 8 ++++ .../test_vertex_ai_gemini_transformation.py | 37 +++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/litellm/llms/vertex_ai/gemini/transformation.py b/litellm/llms/vertex_ai/gemini/transformation.py index 7945c44d44c..41cead57739 100644 --- a/litellm/llms/vertex_ai/gemini/transformation.py +++ b/litellm/llms/vertex_ai/gemini/transformation.py @@ -208,6 +208,14 @@ def _process_gemini_media( return _apply_gemini_3_metadata( part, model, media_resolution_enum, video_metadata ) + elif "https://generativelanguage.googleapis.com/v1beta/files/" in image_url: + # Gemini Files API URI — mime type is already known by the API, + # no need to resolve it from the URL (which would cause a 403). + file_data = FileDataType(file_uri=image_url) + part = {"file_data": file_data} + return _apply_gemini_3_metadata( + part, model, media_resolution_enum, video_metadata + ) elif ( "https://" in image_url and (image_type := format or _get_image_mime_type_from_url(image_url)) diff --git a/tests/test_litellm/llms/vertex_ai/gemini/test_vertex_ai_gemini_transformation.py b/tests/test_litellm/llms/vertex_ai/gemini/test_vertex_ai_gemini_transformation.py index ce3d2daa743..1f3841b6738 100644 --- a/tests/test_litellm/llms/vertex_ai/gemini/test_vertex_ai_gemini_transformation.py +++ b/tests/test_litellm/llms/vertex_ai/gemini/test_vertex_ai_gemini_transformation.py @@ -3,6 +3,7 @@ from litellm.litellm_core_utils.prompt_templates.factory import ( ) from litellm.llms.vertex_ai.gemini.transformation import ( _gemini_convert_messages_with_history, + _process_gemini_media, _transform_request_body, check_if_part_exists_in_parts, _get_highest_media_resolution, @@ -1812,3 +1813,39 @@ def test_multi_turn_function_calling_roles(): assert ( content["role"] == "user" ), f"Content block {i} with function_response has role='{content['role']}', expected 'user'" + + +def test_process_gemini_media_files_api_uri_no_mime_type_required(): + """ + Regression test for https://github.com/BerriAI/litellm/issues/24907. + + Gemini Files API URIs (https://generativelanguage.googleapis.com/v1beta/files/*) + must be forwarded as file_data without attempting to resolve a mime type from the + URL. The URL has no file extension and the endpoint returns 403 for unauthenticated + requests, so any attempt to download or sniff the mime type raises an error. + """ + gemini_file_uri = ( + "https://generativelanguage.googleapis.com/v1beta/files/37eh7rsw1vfe" + ) + + part = _process_gemini_media(image_url=gemini_file_uri) + + assert "file_data" in part + assert part["file_data"]["file_uri"] == gemini_file_uri + # mime_type must NOT be set — the Files API already knows the type + assert part["file_data"].get("mime_type") is None + + +def test_process_gemini_media_files_api_uri_with_explicit_format(): + """ + When the caller explicitly provides a format/mime type for a Gemini Files API URI, + it should still be forwarded as file_data (not attempted as an inline download). + """ + gemini_file_uri = ( + "https://generativelanguage.googleapis.com/v1beta/files/n1vhxa28lyaw" + ) + + part = _process_gemini_media(image_url=gemini_file_uri, format="text/plain") + + assert "file_data" in part + assert part["file_data"]["file_uri"] == gemini_file_uri