diff --git a/litellm/images/main.py b/litellm/images/main.py index 6a94e7c8df2..18255e88c24 100644 --- a/litellm/images/main.py +++ b/litellm/images/main.py @@ -64,6 +64,9 @@ from litellm.utils import ( # Cache for ImageEditRequestUtils to avoid repeated __getattr__ calls _ImageEditRequestUtils_cache: Optional["ImageEditRequestUtils"] = None +# Kept out of all_litellm_params because that list is stripped before drop_params is applied. +_IMAGE_EDIT_CONTROL_KWARGS: Final = frozenset(("drop_params", "additional_drop_params")) + def _get_ImageEditRequestUtils() -> "ImageEditRequestUtils": """Get ImageEditRequestUtils, loading it lazily if needed.""" @@ -759,8 +762,8 @@ def image_edit( litellm_params_list: Final = all_litellm_params default_params: Final = openai_params + litellm_params_list non_default_params: Final = { - k: v for k, v in kwargs.items() if k not in default_params - } # model-specific params - pass them straight to the model/provider + k: v for k, v in kwargs.items() if k not in default_params and k not in _IMAGE_EDIT_CONTROL_KWARGS + } litellm_logging_obj: Final[LiteLLMLoggingObj] = kwargs.get("litellm_logging_obj") litellm_call_id: Final[str | None] = kwargs.get("litellm_call_id", None) model_info: Final = kwargs.get("model_info", None) diff --git a/tests/test_litellm/images/test_image_edit_extra_params.py b/tests/test_litellm/images/test_image_edit_extra_params.py index 088faafa9f3..1d1fce2bf63 100644 --- a/tests/test_litellm/images/test_image_edit_extra_params.py +++ b/tests/test_litellm/images/test_image_edit_extra_params.py @@ -121,6 +121,35 @@ def test_image_edit_forwards_scalar_array_as_repeated_fields(): assert b"style_a" in body and b"style_b" in body and b"style_c" in body +@pytest.mark.parametrize("drop_params", [True, False]) +def test_image_edit_strips_per_model_drop_params_from_multipart(drop_params): + """Per-model drop_params / additional_drop_params are LiteLLM control + flags. If they survive into non_default_params they are flattened onto the + OpenAI images/edits multipart body and the provider rejects the call with + Unknown parameter: 'drop_params'. Issue #40153.""" + captured = {} + client = HTTPHandler(client=httpx.Client(transport=httpx.MockTransport(_capture_image_edit_request(captured)))) + + litellm.image_edit( + model="openai/gpt-image-1", + image=PNG_BYTES, + prompt="Make the background blue", + api_key="sk-test", + api_base="https://edit.example/v1", + client=client, + seed=42, + drop_params=drop_params, + additional_drop_params=["quality_level"], + ) + + fields = _multipart_text_fields(captured["content_type"], captured["body"]) + assert "drop_params" not in fields + assert "additional_drop_params" not in fields + assert fields["seed"] == "42" + assert fields["prompt"] == "Make the background blue" + assert fields["model"] == "gpt-image-1" + + @pytest.mark.asyncio async def test_aimage_edit_forwards_extra_body(): """aimage_edit used to drop extra_headers/extra_query/extra_body when