From 8a23564d6e5ab1fda298bc661b05ab9b733f0a0e Mon Sep 17 00:00:00 2001 From: milan Date: Thu, 13 Aug 2026 22:42:57 +0000 Subject: [PATCH] fix(vertex passthrough): keep transport failures out of the auth error mapping Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../llm_passthrough_endpoints.py | 5 ++- .../test_vertex_passthrough_load_balancing.py | 43 ++++++++++++++++++- 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py b/litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py index 69126b5fd6f..061e60a2e32 100644 --- a/litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py +++ b/litellm/proxy/pass_through_endpoints/llm_passthrough_endpoints.py @@ -14,6 +14,7 @@ from typing import Any, Final, cast import httpx from fastapi import APIRouter, Depends, HTTPException, Request, Response, WebSocket from fastapi.responses import StreamingResponse +from google.auth.exceptions import GoogleAuthError, TransportError from starlette.websockets import WebSocketState import litellm @@ -1616,7 +1617,9 @@ async def _prepare_vertex_auth_headers( custom_llm_provider="vertex_ai_beta", api_base="", ) - except Exception as e: + except TransportError: + raise + except (GoogleAuthError, ValueError) as e: raise ProxyException( message=( f"Failed to get a Google access token for project={vertex_project} + location={vertex_location}: {e}. " diff --git a/tests/test_litellm/proxy/pass_through_endpoints/test_vertex_passthrough_load_balancing.py b/tests/test_litellm/proxy/pass_through_endpoints/test_vertex_passthrough_load_balancing.py index 8e16fcf66f6..8b3c6bfd292 100644 --- a/tests/test_litellm/proxy/pass_through_endpoints/test_vertex_passthrough_load_balancing.py +++ b/tests/test_litellm/proxy/pass_through_endpoints/test_vertex_passthrough_load_balancing.py @@ -1,12 +1,11 @@ from unittest.mock import AsyncMock, MagicMock, patch import pytest -from google.auth.exceptions import DefaultCredentialsError +from google.auth.exceptions import DefaultCredentialsError, TransportError from litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints import ( _base_vertex_proxy_route, ) -from litellm.types.router import DeploymentTypedDict @pytest.mark.asyncio @@ -396,6 +395,46 @@ async def test_vertex_passthrough_credential_failure_raises_auth_error(): assert "Your default credentials were not found" in exc_info.value.message +@pytest.mark.asyncio +async def test_vertex_passthrough_transport_failure_is_not_reported_as_auth_error(): + """ + Reaching Google's token endpoint can fail for reasons the operator cannot fix with + credentials, so those must not be relabelled as authentication errors. + """ + from starlette.datastructures import Headers + + from litellm.llms.vertex_ai.vertex_llm_base import VertexBase + from litellm.proxy.pass_through_endpoints.llm_passthrough_endpoints import ( + _prepare_vertex_auth_headers, + ) + + mock_request = MagicMock() + mock_request.headers = Headers({"authorization": "Bearer sk-litellm-key"}) + mock_request.state._cached_headers = None + + mock_vertex_credentials = MagicMock() + mock_vertex_credentials.vertex_project = "test-project" + mock_vertex_credentials.vertex_location = "us-central1" + mock_vertex_credentials.vertex_credentials = None + + with patch.object( + VertexBase, + "_ensure_access_token_async", + new_callable=AsyncMock, + side_effect=TransportError("connection reset by peer"), + ): + with pytest.raises(TransportError): + await _prepare_vertex_auth_headers( + request=mock_request, + vertex_credentials=mock_vertex_credentials, + router_credentials=None, + vertex_project="test-project", + vertex_location="us-central1", + base_target_url="https://us-central1-aiplatform.googleapis.com", + get_vertex_pass_through_handler=MagicMock(), + ) + + @pytest.mark.asyncio async def test_vertex_passthrough_does_not_forward_litellm_auth_token(): """