Skip to content

fix(vertex_ai/gemini): MIME detection for extensionless GCS URIs + async event-loop fix - #27715

Closed
krrish-berri-2 wants to merge 5 commits into
litellm_internal_stagingfrom
cursor/fix-greptile-feedback-27278-5b9c
Closed

fix(vertex_ai/gemini): MIME detection for extensionless GCS URIs + async event-loop fix#27715
krrish-berri-2 wants to merge 5 commits into
litellm_internal_stagingfrom
cursor/fix-greptile-feedback-27278-5b9c

Conversation

@krrish-berri-2

Copy link
Copy Markdown
Contributor

Relevant issues

Fixes Gemini MIME detection for extensionless gs:// media URIs, and propagates litellm_params so private GCS objects can be resolved via authenticated metadata lookup.

Addresses Greptile feedback on #27278.

Pre-Submission checklist

  • I have Added testing in the tests/test_litellm/ directory, Adding at least 1 test is a hard requirement - see details
  • My PR passes all unit tests on make test-unit
  • My PR's scope is as isolated as possible, it only solves 1 specific problem

Type

🐛 Bug Fix
✅ Test

Changes

Problem

  • When a gs:// URI has no file extension, Gemini's current MIME inference fails, which causes the media payload to be rejected or mistyped.
  • litellm_params (including vertex_project / vertex_credentials) was not propagated into the message transformation layer, so authenticated GCS metadata lookups could not be performed for private objects.

Fix

Core logic:

  • Resolve contentType from GCS object metadata when the gs:// URI is extensionless using a new _get_gcs_object_content_type helper
  • Preserve compatibility with explicit MIME inputs: format, mime_type, content_type
  • Propagate litellm_params from the request body down into the message transformation layer, carrying vertex_project / vertex_credentials through

Greptile feedback addressed:

  1. Async event loop: The sync httpx.get GCS metadata call is now offloaded to a worker thread via asyncify(_transform_request_body) in async_transform_request_body, so it cannot block the event loop. A dedicated test (test_async_transform_request_body_does_not_block_event_loop) verifies this with a 0.5s simulated blocking call and confirms a concurrent asyncio.sleep(0.05) completes without delay.
  2. All tests are properly mocked: Every new test patches _get_gcs_object_content_type or httpx.get — no real outbound HTTP calls are made.

Security

  • Only attaches a Bearer token when the caller explicitly supplies Vertex credentials, preventing use of server-default Google credentials on the Google AI Studio path (per veria-ai review).
  • GCS metadata URL is constructed via httpx.URL with URL-encoded bucket/object names to prevent SSRF.

Affected files

  • litellm/llms/vertex_ai/gemini/transformation.py
  • litellm/llms/gemini/chat/transformation.py
  • litellm/llms/vertex_ai/gemini/vertex_and_google_ai_studio_gemini.py
  • tests/test_litellm/llms/vertex_ai/test_vertex.py

Tests

All 40 unit tests in tests/test_litellm/llms/vertex_ai/test_vertex.py pass, including:

  • Explicit MIME success path
  • Metadata-based MIME resolution success path
  • image/jpgimage/jpeg alias normalization
  • Rejection of unsupported metadata MIME types with a clear BadRequestError
  • Credential propagation and auth-token attachment
  • Anonymous (no-credentials) path that skips auth token
  • Event-loop non-blocking proof test
Open in Web Open in Cursor 

S0ngRu1 and others added 5 commits May 12, 2026 04:04
Propagate litellm_params across Gemini transformers, resolve MIME from GCS metadata for extensionless gs:// objects, normalize file MIME aliases (format/mime_type/content_type), improve error mapping to BadRequestError, and add regression coverage for explicit MIME, metadata success, and file_data error-message behavior.

Made-with: Cursor
…nt loop

Address PR #27278 review feedback:
- async_transform_request_body now runs the sync _transform_request_body
  (which may issue an httpx.get with up to 5s timeout for GCS metadata) in
  a worker thread via asyncify, so extensionless gs:// URIs no longer block
  the event loop on the async path.
- Drop redundant `pass` in _get_gcs_object_content_type's except block.
- Mock _get_gcs_object_content_type in
  test_process_gemini_media_gcs_without_extension_raises_clear_error so
  the test no longer makes real network calls.
- Add a regression test that verifies async_transform_request_body does
  not block the event loop while the sync GCS metadata fetch is slow.
Address CodeQL alerts introduced in #27278:

- Defer VertexBase import into a lazy helper to break the module-level
  cyclic import between transformation and vertex_llm_base. This also
  clears the downstream cyclic-import alerts on
  vertex_and_google_ai_studio_gemini.py. _GCS_METADATA_VERTEX_BASE is
  kept as a module attribute so existing patch.object tests still work.
- Move get_file_extension_from_mime_type to a function-local import to
  drop the cyclic-import alert on litellm.types.files.
- Build the GCS metadata URL with httpx.URL and url-encode the bucket
  so the fully-qualified host is obvious to CodeQL, clearing the
  partial SSRF alert.
- mypy: cast image_url/file dict to Dict[str, Any] before reading
  mime_type/content_type, since those keys are not declared on the
  ChatCompletionImageUrlObject / ChatCompletionFileObjectFile TypedDicts
  and mypy was inferring `object` for the fallback-or chain, failing
  the lint job.
- security (veria-ai review): in _get_gcs_object_content_type, only
  call VertexBase.get_access_token when the caller explicitly passes
  vertex_project/vertex_credentials. Without explicit credentials we
  now skip the authenticated call entirely and only attempt an
  anonymous metadata lookup, so a Gemini API-key / Google AI Studio
  caller can no longer trick the proxy into querying GCS with the
  server's default Google credentials.
- Add regression test covering the no-credentials path (no ADC token
  requested, no Authorization header on the outbound metadata call).
Translate the Chinese comments and docstrings introduced in this PR to
English to match the repository convention for upstream BerriAI/litellm.
No behavior change.
@codecov

codecov Bot commented May 12, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 78.00000% with 22 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
litellm/llms/vertex_ai/gemini/transformation.py 77.55% 22 Missing ⚠️

📢 Thoughts on this report? Let us know!

@github-actions

Copy link
Copy Markdown
Contributor

This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.

@github-actions github-actions Bot added the stale label Aug 11, 2026
@github-actions github-actions Bot closed this Aug 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants