diff --git a/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py b/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py index 54c3f9e0474..d65ae01df06 100644 --- a/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py +++ b/litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/experimental_pass_through/transformation.py @@ -31,10 +31,11 @@ class VertexAIPartnerModelsAnthropicMessagesConfig(AnthropicMessagesConfig, Vert Validate the environment for the request """ + vertex_ai_project = VertexBase.safe_get_vertex_ai_project(litellm_params) + vertex_ai_location = VertexBase.safe_get_vertex_ai_location(litellm_params) + if "Authorization" not in headers: - vertex_ai_project = VertexBase.get_vertex_ai_project(litellm_params) - vertex_credentials = VertexBase.get_vertex_ai_credentials(litellm_params) - vertex_ai_location = VertexBase.get_vertex_ai_location(litellm_params) + vertex_credentials = VertexBase.safe_get_vertex_ai_credentials(litellm_params) access_token, project_id = self._ensure_access_token( credentials=vertex_credentials, @@ -43,7 +44,12 @@ class VertexAIPartnerModelsAnthropicMessagesConfig(AnthropicMessagesConfig, Vert ) headers["Authorization"] = f"Bearer {access_token}" + else: + # Authorization already in headers, but we still need project_id + project_id = vertex_ai_project + # Always calculate api_base if not provided, regardless of Authorization header + if api_base is None: api_base = self.get_complete_vertex_url( custom_api_base=api_base, vertex_location=vertex_ai_location, diff --git a/tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_messages_config.py b/tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_messages_config.py index 7bb84b0a2c1..b5f076262d7 100644 --- a/tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_messages_config.py +++ b/tests/test_litellm/llms/vertex_ai/vertex_ai_partner_models/anthropic/test_vertex_ai_partner_models_anthropic_messages_config.py @@ -215,3 +215,36 @@ def test_both_compact_and_context_management_headers_added(): f"anthropic-beta should contain 'compact-2026-01-12', got: {updated_headers['anthropic-beta']}" assert "context-management-2025-06-27" in updated_headers["anthropic-beta"], \ f"anthropic-beta should contain 'context-management-2025-06-27', got: {updated_headers['anthropic-beta']}" + +def test_validate_environment_with_authorization_header_calculates_api_base(): + """Test that api_base is calculated even when Authorization header is already present""" + config = VertexAIPartnerModelsAnthropicMessagesConfig() + # Simulate scenario where Authorization is already in headers (e.g., from cached extra_headers) + headers = {"Authorization": "Bearer existing-token"} + litellm_params = { + "vertex_project": "test-project", + "vertex_location": "us-central1", + "extra_headers": {"anthropic-beta": "context-1m-2025-08-07"}, + } + optional_params = {} + + with patch.object( + config, "get_complete_vertex_url", return_value="https://mock-vertex-url" + ) as mock_get_url: + updated_headers, api_base = config.validate_anthropic_messages_environment( + headers=headers, + model="claude-sonnet-4", + messages=[], + optional_params=optional_params, + litellm_params=litellm_params, + api_base=None, + ) + + # Verify that api_base was calculated even though Authorization was already present + assert api_base == "https://mock-vertex-url", \ + f"api_base should be calculated even with Authorization header. Got: {api_base}" + assert mock_get_url.called, "get_complete_vertex_url should be called" + + # Verify Authorization header is still present + assert "Authorization" in updated_headers, \ + "Authorization header should be preserved"