fix(utils): stop a nested additional_drop_params entry from crashing openai-compatible calls (#42492)

add_provider_specific_params_to_optional_params built the extra_body dropped-key
set as frozenset(additional_drop_params), so one non-string entry raised
TypeError: unhashable type: 'list' and every openai-compatible call carrying one
failed with a 500 before it reached the transport. The set now takes only the
string entries, the element type every other signature in this chain already
declares as list[str].

A list-form entry still drops nothing: is_nested_path() tests a string, so
delete_nested_value() has never applied one on any provider. This removes the
crash only, so a working string path such as "tools[*].function.x" sitting
beside a malformed list entry is applied instead of taking the request down.
This commit is contained in:
yuneng-jiang 2026-09-22 10:50:49 -07:00 • committed by GitHub
parent 4b65ef6d64
commit d47e72f66c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 42 additions and 1 deletions

View file

@ -4979,7 +4979,9 @@ def add_provider_specific_params_to_optional_params(
**extra_body,
}
dropped_keys: Final = EXTRA_BODY_ROUTING_KEYS | frozenset(additional_drop_params or ())
dropped_keys: Final = EXTRA_BODY_ROUTING_KEYS | frozenset(
param for param in (additional_drop_params or ()) if isinstance(param, str)
)
processed_extra_body: Final = {k: v for k, v in initial_extra_body.items() if k not in dropped_keys}
_ensure_extra_body_is_safe: Final = getattr(sys.modules[__name__], "_ensure_extra_body_is_safe")

View file

@ -3042,6 +3042,45 @@ class TestExtraBodyCannotOverrideModel:
assert result["extra_body"] == {"top_k": 5}, result
def test_nested_drop_paths_do_not_break_extra_body_filtering(self) -> None:
from litellm.utils import add_provider_specific_params_to_optional_params
result = add_provider_specific_params_to_optional_params(
optional_params={},
passed_params={
"model": "hosted_vllm/my-vllm-model",
"extra_body": {"model": "hosted_vllm/other", "top_k": 5, "kept": True},
},
custom_llm_provider="hosted_vllm",
openai_params=["model", "temperature"],
additional_drop_params=[["tools", "function", "strict"], "top_k"],
)
assert result == {"extra_body": {"kept": True}}, result
def test_a_list_entry_does_not_break_a_supported_nested_drop_path(self) -> None:
def tools() -> list[dict]:
return [
{
"type": "function",
"function": {"name": "f", "custom_marker": "LEAK", "parameters": {"type": "object"}},
}
]
untouched = litellm.get_optional_params(
model="my-vllm-model", custom_llm_provider="hosted_vllm", tools=tools()
)
assert untouched["tools"][0]["function"]["custom_marker"] == "LEAK", untouched
result = litellm.get_optional_params(
model="my-vllm-model",
custom_llm_provider="hosted_vllm",
tools=tools(),
additional_drop_params=["tools[*].function.custom_marker", ["tools", "function", "custom_marker"]],
)
assert "custom_marker" not in result["tools"][0]["function"], result
class TestDropParamsWithPromptCacheKey:
"""