diff --git a/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py b/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py index e5698843e8f..328c3a0b977 100644 --- a/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py +++ b/litellm/llms/bedrock/chat/invoke_transformations/anthropic_claude3_transformation.py @@ -108,6 +108,9 @@ class AmazonAnthropicClaudeConfig(AmazonInvokeConfig, AnthropicConfig): _anthropic_request.pop("stream", None) # Bedrock Invoke doesn't support output_format parameter _anthropic_request.pop("output_format", None) + # Bedrock Invoke doesn't support output_config parameter + # Fixes: https://github.com/BerriAI/litellm/issues/22797 + _anthropic_request.pop("output_config", None) if "anthropic_version" not in _anthropic_request: _anthropic_request["anthropic_version"] = self.anthropic_version diff --git a/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py b/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py index 9fae5fd2a17..b11215e7f6b 100644 --- a/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py +++ b/litellm/llms/bedrock/messages/invoke_transformations/anthropic_claude3_transformation.py @@ -419,6 +419,10 @@ class AmazonAnthropicClaudeMessagesConfig( anthropic_messages_request=anthropic_messages_request, ) + # 5b. Strip `output_config` — Bedrock Invoke doesn't support it + # Fixes: https://github.com/BerriAI/litellm/issues/22797 + anthropic_messages_request.pop("output_config", None) + # 5a. Remove `custom` field from tools (Bedrock doesn't support it) # Claude Code sends `custom: {defer_loading: true}` on tool definitions, # which causes Bedrock to reject the request with "Extra inputs are not permitted" diff --git a/tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py b/tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py index d2fb45643de..cb05531c2f8 100644 --- a/tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py +++ b/tests/test_litellm/llms/bedrock/chat/invoke_transformations/test_bedrock_chat_invoke_transformations_anthropic_claude3_transformation.py @@ -386,6 +386,40 @@ def test_opus_4_5_model_detection(): # f"computer-use beta should be kept, got: {anthropic_beta}" +def test_output_config_removed_from_bedrock_chat_invoke_request(): + """ + Test that output_config parameter is stripped from Bedrock Chat Invoke requests. + + Bedrock Invoke API doesn't support the output_config parameter (Anthropic-only). + Ensures the chat/invoke path mirrors the messages/invoke path fix. + + Fixes: https://github.com/BerriAI/litellm/issues/22797 + """ + config = AmazonAnthropicClaudeConfig() + + messages = [{"role": "user", "content": "test"}] + + # Inject output_config into optional_params (simulates Anthropic SDK forwarding it) + optional_params = { + "max_tokens": 100, + "output_config": {"effort": "high"}, + } + + result = config.transform_request( + model="anthropic.claude-sonnet-4-20250514-v1:0", + messages=messages, + optional_params=optional_params, + litellm_params={}, + headers={}, + ) + + assert "output_config" not in result, ( + f"output_config should be stripped for Bedrock Chat Invoke, got keys: {list(result.keys())}" + ) + # Verify normal params survive + assert result["max_tokens"] == 100 + + def test_output_format_removed_from_bedrock_invoke_request(): """ Test that output_format parameter is removed from Bedrock Invoke requests. diff --git a/tests/test_litellm/llms/bedrock/messages/invoke_transformations/test_anthropic_claude3_transformation.py b/tests/test_litellm/llms/bedrock/messages/invoke_transformations/test_anthropic_claude3_transformation.py index e0b06ced172..f69f478278f 100644 --- a/tests/test_litellm/llms/bedrock/messages/invoke_transformations/test_anthropic_claude3_transformation.py +++ b/tests/test_litellm/llms/bedrock/messages/invoke_transformations/test_anthropic_claude3_transformation.py @@ -275,3 +275,70 @@ def test_remove_scope_from_cache_control(): # Verify scope is removed from messages assert "scope" not in request["messages"][0]["content"][0]["cache_control"] assert request["messages"][0]["content"][0]["cache_control"]["type"] == "ephemeral" + + +def test_bedrock_messages_strips_output_config(): + """ + Ensure output_config is stripped from the request before sending to + Bedrock Invoke, which doesn't support this Anthropic-specific parameter. + + Regression test for: https://github.com/BerriAI/litellm/issues/22797 + """ + from litellm.types.router import GenericLiteLLMParams + + cfg = AmazonAnthropicClaudeMessagesConfig() + messages = [{"role": "user", "content": [{"type": "text", "text": "Hello"}]}] + optional_params = { + "max_tokens": 4096, + "output_config": { + "effort": "high", + }, + } + + result = cfg.transform_anthropic_messages_request( + model="anthropic.claude-3-haiku-20240307-v1:0", + messages=messages, + anthropic_messages_optional_request_params=optional_params, + litellm_params=GenericLiteLLMParams(), + headers={}, + ) + + assert "output_config" not in result, ( + "output_config should be stripped — Bedrock Invoke rejects it" + ) + # Other params should be preserved + assert result.get("max_tokens") == 4096 + + +def test_bedrock_messages_strips_output_config_with_output_format(): + """ + When both output_config and output_format are present, both should be + stripped (output_format is converted to inline schema, output_config + is simply dropped). + """ + from litellm.types.router import GenericLiteLLMParams + + cfg = AmazonAnthropicClaudeMessagesConfig() + messages = [{"role": "user", "content": [{"type": "text", "text": "Hello"}]}] + optional_params = { + "max_tokens": 4096, + "output_config": {"effort": "low"}, + "output_format": { + "type": "json_schema", + "schema": { + "type": "object", + "properties": {"answer": {"type": "string"}}, + }, + }, + } + + result = cfg.transform_anthropic_messages_request( + model="anthropic.claude-3-haiku-20240307-v1:0", + messages=messages, + anthropic_messages_optional_request_params=optional_params, + litellm_params=GenericLiteLLMParams(), + headers={}, + ) + + assert "output_config" not in result + assert "output_format" not in result