fix(vertex_ai): drop unsupported output_config parameter from all requests

Vertex AI does not support the output_config parameter in its API.
This parameter is being added by Anthropic/Gemini transformations but needs
to be removed before sending requests to Vertex AI endpoints.

This fix addresses the "Extra inputs are not permitted" error (issue #22312)
when using Claude models with structured outputs on Vertex AI.

Changes:
- Drop output_config in Gemini model transformation
- Drop output_config in Anthropic partner model transformation
- Drop output_config in Anthropic experimental pass-through transformation
- Add comprehensive tests to verify output_config is dropped

Fixes: #22312
Made-with: Cursor
This commit is contained in:
Sameer Kankute 2026-03-05 13:02:17 +05:30
parent cdf2d67fc8
commit a2c11d431a
4 changed files with 118 additions and 0 deletions

View file

@ -595,6 +595,8 @@ def _transform_request_body(
safety_settings: Optional[List[SafetSettingsConfig]] = optional_params.pop(
"safety_settings", None
) # type: ignore
# Drop output_config as it's not supported by Vertex AI
optional_params.pop("output_config", None)
config_fields = GenerationConfig.__annotations__.keys()
# If the LiteLLM client sends Gemini-supported parameter "labels", add it

View file

@ -152,4 +152,8 @@ class VertexAIPartnerModelsAnthropicMessagesConfig(AnthropicMessagesConfig, Vert
"output_format", None
) # do not pass output_format in request body to vertex ai - vertex ai does not support output_format as yet
anthropic_messages_request.pop(
"output_config", None
) # do not pass output_config in request body to vertex ai - vertex ai does not support output_config
return anthropic_messages_request

View file

@ -107,6 +107,9 @@ class VertexAIAnthropicConfig(AnthropicConfig):
# VertexAI doesn't support output_format parameter, remove it if present
data.pop("output_format", None)
# VertexAI doesn't support output_config parameter, remove it if present
data.pop("output_config", None)
tools = optional_params.get("tools")
tool_search_used = self.is_tool_search_used(tools)

View file

@ -489,3 +489,112 @@ def test_vertex_ai_partner_models_anthropic_remove_prompt_caching_scope_beta_hea
assert (
"anthropic-beta" not in headers2
), "Header should be removed if no supported values remain"
def test_vertex_ai_anthropic_output_config_dropped():
"""
Test that output_config parameter is dropped from Vertex AI Anthropic requests.
Vertex AI does not support the output_config parameter (used for effort settings
in Anthropic API). This test ensures it's properly removed to prevent
"Extra inputs are not permitted" errors.
"""
config = VertexAIAnthropicConfig()
messages = [{"role": "user", "content": "What is 2+2?"}]
headers = {}
# Simulate optional_params with output_config that would be passed in
optional_params = {
"max_tokens": 1024,
"output_config": {
"effort": "high" # This is Anthropic-specific and not supported by Vertex AI
},
}
# Call transform_request which should drop output_config
result = config.transform_request(
model="claude-3-5-sonnet-20241022",
messages=messages,
optional_params=optional_params,
litellm_params={},
headers=headers,
)
# Verify output_config was removed
assert "output_config" not in result, \
"output_config should be dropped from Vertex AI Anthropic requests"
# Verify other parameters are preserved
assert result["max_tokens"] == 1024, "max_tokens should be preserved"
assert "messages" in result, "messages should be present"
def test_vertex_ai_anthropic_output_format_and_output_config_both_dropped():
"""
Test that both output_format and output_config are dropped from Vertex AI requests.
This ensures that even if both parameters somehow make it to the transform_request,
they are properly cleaned up before sending to Vertex AI.
"""
config = VertexAIAnthropicConfig()
messages = [{"role": "user", "content": "Extract structured data"}]
headers = {}
optional_params = {
"max_tokens": 2048,
"output_format": {
"type": "json_schema",
"json_schema": {
"name": "data",
"schema": {"type": "object", "properties": {"result": {"type": "string"}}}
}
},
"output_config": {
"effort": "high"
},
}
# Simulate parent class creating test_data with both parameters
# (as if the parent transform_request added them)
test_data = {
"model": "claude-3-5-sonnet-20241022",
"messages": messages,
"max_tokens": 2048,
"output_format": optional_params["output_format"],
"output_config": optional_params["output_config"],
}
# Mock the parent transform_request to return data with both parameters
original_transform = config.__class__.__bases__[0].transform_request
def mock_transform_request(self, model, messages, optional_params, litellm_params, headers):
return test_data.copy()
config.__class__.__bases__[0].transform_request = mock_transform_request
try:
result = config.transform_request(
model="claude-3-5-sonnet-20241022",
messages=messages,
optional_params=optional_params,
litellm_params={},
headers=headers,
)
# Verify both were removed
assert "output_format" not in result, \
"output_format should be dropped from Vertex AI requests"
assert "output_config" not in result, \
"output_config should be dropped from Vertex AI requests"
# Verify essential params are preserved
assert result["max_tokens"] == 2048, "max_tokens should be preserved"
assert "messages" in result, "messages should be present"
assert "model" not in result, "model should also be dropped for Vertex AI"
finally:
# Restore original method
config.__class__.__bases__[0].transform_request = original_transform