fix(bedrock): drop internal MCP params from Invoke request bodies

The Invoke transform deep-copied optional_params, stripped AWS auth keys, then
splatted the remainder straight into the provider request body. LiteLLM-internal
MCP control flags (skip_mcp_handler, _skip_mcp_handler, mcp_handler_context) are
not Bedrock inference parameters, so they reached AWS and the request was
rejected with "Extra inputs are not permitted". Non-Anthropic Invoke models
(mistral, titan, ai21, llama, cohere) all build their body off these
inference_params, so every one of them leaked.

Route inference_params through the shared filter_internal_params helper, the
same guard the Converse path already applies, so the internal keys are removed
at the single point where the body is assembled

Fixes #30371
This commit is contained in:
mateo-berri 2026-06-18 15:33:03 +00:00
parent a9e651d994
commit 367e8b6192
2 changed files with 46 additions and 7 deletions

View file

@ -8,7 +8,10 @@ import httpx
import litellm
from litellm._logging import verbose_logger
from litellm.litellm_core_utils.core_helpers import map_finish_reason
from litellm.litellm_core_utils.core_helpers import (
filter_internal_params,
map_finish_reason,
)
from litellm.litellm_core_utils.logging_utils import track_llm_api_timing
from litellm.litellm_core_utils.prompt_templates.factory import (
cohere_message_pt,
@ -162,12 +165,13 @@ class AmazonInvokeConfig(BaseConfig, BaseAWSLLM):
provider=provider,
custom_prompt_dict=custom_prompt_dict,
)
inference_params = copy.deepcopy(optional_params)
inference_params = {
k: v
for k, v in inference_params.items()
if k not in self.aws_authentication_params
}
inference_params = filter_internal_params(
{
k: v
for k, v in copy.deepcopy(optional_params).items()
if k not in self.aws_authentication_params
}
)
request_data: dict = {}
if provider == "cohere":
if model.startswith("cohere.command-r"):

View file

@ -39,3 +39,38 @@ def test_transform_request_drops_stream_chunk_size(config, model):
)
assert "stream_chunk_size" not in json.dumps(request_body)
@pytest.mark.parametrize(
"model",
[
"mistral.mistral-7b-instruct-v0:2",
"amazon.titan-text-express-v1",
"ai21.j2-ultra-v1",
"meta.llama3-8b-instruct-v1:0",
],
)
def test_transform_request_drops_internal_mcp_params(model):
"""skip_mcp_handler, _skip_mcp_handler and mcp_handler_context are
LiteLLM-internal MCP control flags, not Bedrock inference parameters. The
invoke path splats inference_params straight into the request body, so
without filtering they reach AWS and the request is rejected with
'extraneous key is not permitted'. Regression for
https://github.com/BerriAI/litellm/issues/30371."""
request_body = AmazonInvokeConfig().transform_request(
model=model,
messages=[{"role": "user", "content": "hi"}],
optional_params={
"max_tokens": 10,
"skip_mcp_handler": True,
"_skip_mcp_handler": True,
"mcp_handler_context": {"server": "x"},
},
litellm_params={},
headers={},
)
serialized = json.dumps(request_body)
assert "skip_mcp_handler" not in serialized
assert "mcp_handler_context" not in serialized
assert "max_tokens" in serialized