From dff4bfd735946e1006d33adef0286e557b6f0b62 Mon Sep 17 00:00:00 2001 From: Sameer Kankute Date: Tue, 21 Apr 2026 14:54:18 +0530 Subject: [PATCH] fix(image_edit): forward litellm_params to validate_environment for Vertex AI credentials When aimage_edit or image_edit was called with Vertex AI Gemini/Imagen models via YAML-style config (vertex_project / vertex_credentials in proxy YAML), the credentials were dropped during handler-to-config plumbing, causing fallback to Application Default Credentials and DefaultCredentialsError. Root cause: image_edit_handler and async_image_edit_handler did not pass litellm_params to validate_environment, unlike image_generation_handler. Fixes: 1. Widen BaseImageEditConfig.validate_environment signature to accept litellm_params and api_base (optional kwargs). 2. Forward dict(litellm_params) and litellm_params.api_base from both sync and async image_edit handlers to validate_environment. 3. Update VertexAIImagenImageEditConfig.validate_environment to read vertex_ai_project/vertex_ai_credentials from litellm_params first, matching Gemini config pattern (secondary latent bug fix). 4. Widen all image-edit config override signatures to match base. Made-with: Cursor --- .../llms/azure/image_edit/transformation.py | 2 ++ .../image_edit/flux2_transformation.py | 2 ++ .../llms/azure_ai/image_edit/transformation.py | 2 ++ .../llms/base_llm/image_edit/transformation.py | 2 ++ ...on_nova_canvas_image_edit_transformation.py | 2 ++ .../image_edit/stability_transformation.py | 2 ++ .../image_edit/transformation.py | 2 ++ litellm/llms/custom_httpx/llm_http_handler.py | 4 ++++ .../llms/gemini/image_edit/transformation.py | 2 ++ .../litellm_proxy/image_edit/transformation.py | 7 ++++++- .../llms/openai/image_edit/transformation.py | 2 ++ .../openrouter/image_edit/transformation.py | 2 ++ .../llms/recraft/image_edit/transformation.py | 2 ++ .../stability/image_edit/transformations.py | 2 ++ .../image_edit/vertex_imagen_transformation.py | 18 ++++++++++++++++-- .../images/test_image_edit_utils.py | 9 +++++++-- 16 files changed, 57 insertions(+), 5 deletions(-) diff --git a/litellm/llms/azure/image_edit/transformation.py b/litellm/llms/azure/image_edit/transformation.py index f476d6a94e..dffa1c9eea 100644 --- a/litellm/llms/azure/image_edit/transformation.py +++ b/litellm/llms/azure/image_edit/transformation.py @@ -14,6 +14,8 @@ class AzureImageEditConfig(OpenAIImageEditConfig): headers: dict, model: str, api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: api_key = ( api_key diff --git a/litellm/llms/azure_ai/image_edit/flux2_transformation.py b/litellm/llms/azure_ai/image_edit/flux2_transformation.py index 0de163a771..1bc3bdcddc 100644 --- a/litellm/llms/azure_ai/image_edit/flux2_transformation.py +++ b/litellm/llms/azure_ai/image_edit/flux2_transformation.py @@ -65,6 +65,8 @@ class AzureFoundryFlux2ImageEditConfig(OpenAIImageEditConfig): headers: dict, model: str, api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: """ Validate Azure AI Foundry environment and set up authentication diff --git a/litellm/llms/azure_ai/image_edit/transformation.py b/litellm/llms/azure_ai/image_edit/transformation.py index 930b6d4db9..e778348c75 100644 --- a/litellm/llms/azure_ai/image_edit/transformation.py +++ b/litellm/llms/azure_ai/image_edit/transformation.py @@ -25,6 +25,8 @@ class AzureFoundryFluxImageEditConfig(OpenAIImageEditConfig): headers: dict, model: str, api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: """ Validate Azure AI Foundry environment and set up authentication diff --git a/litellm/llms/base_llm/image_edit/transformation.py b/litellm/llms/base_llm/image_edit/transformation.py index b088cdf37f..cea96bde74 100644 --- a/litellm/llms/base_llm/image_edit/transformation.py +++ b/litellm/llms/base_llm/image_edit/transformation.py @@ -67,6 +67,8 @@ class BaseImageEditConfig(ABC): headers: dict, model: str, api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: return {} diff --git a/litellm/llms/bedrock/image_edit/amazon_nova_canvas_image_edit_transformation.py b/litellm/llms/bedrock/image_edit/amazon_nova_canvas_image_edit_transformation.py index f806cd2a81..836a3c606e 100644 --- a/litellm/llms/bedrock/image_edit/amazon_nova_canvas_image_edit_transformation.py +++ b/litellm/llms/bedrock/image_edit/amazon_nova_canvas_image_edit_transformation.py @@ -483,6 +483,8 @@ class BedrockAmazonNovaCanvasImageEditConfig(BaseImageEditConfig): headers: dict, model: str, api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: if headers is None: headers = {} diff --git a/litellm/llms/bedrock/image_edit/stability_transformation.py b/litellm/llms/bedrock/image_edit/stability_transformation.py index 6a8b95e7e3..2d73e47003 100644 --- a/litellm/llms/bedrock/image_edit/stability_transformation.py +++ b/litellm/llms/bedrock/image_edit/stability_transformation.py @@ -372,6 +372,8 @@ class BedrockStabilityImageEditConfig(BaseImageEditConfig): headers: dict, model: str, api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: """ Validate environment for Bedrock Stability image edit. diff --git a/litellm/llms/black_forest_labs/image_edit/transformation.py b/litellm/llms/black_forest_labs/image_edit/transformation.py index c6d8e8298e..4d19885aac 100644 --- a/litellm/llms/black_forest_labs/image_edit/transformation.py +++ b/litellm/llms/black_forest_labs/image_edit/transformation.py @@ -123,6 +123,8 @@ class BlackForestLabsImageEditConfig(BaseImageEditConfig): headers: dict, model: str, api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: """ Validate environment and set up headers for Black Forest Labs. diff --git a/litellm/llms/custom_httpx/llm_http_handler.py b/litellm/llms/custom_httpx/llm_http_handler.py index ea0c05e765..de215b9ae5 100644 --- a/litellm/llms/custom_httpx/llm_http_handler.py +++ b/litellm/llms/custom_httpx/llm_http_handler.py @@ -5216,6 +5216,8 @@ class BaseLLMHTTPHandler: api_key=litellm_params.api_key, headers=image_edit_optional_request_params.get("extra_headers", {}) or {}, model=model, + litellm_params=dict(litellm_params), + api_base=litellm_params.api_base, ) if extra_headers: @@ -5312,6 +5314,8 @@ class BaseLLMHTTPHandler: api_key=litellm_params.api_key, headers=image_edit_optional_request_params.get("extra_headers", {}) or {}, model=model, + litellm_params=dict(litellm_params), + api_base=litellm_params.api_base, ) if extra_headers: diff --git a/litellm/llms/gemini/image_edit/transformation.py b/litellm/llms/gemini/image_edit/transformation.py index d46733e04b..c8aaab0e14 100644 --- a/litellm/llms/gemini/image_edit/transformation.py +++ b/litellm/llms/gemini/image_edit/transformation.py @@ -54,6 +54,8 @@ class GeminiImageEditConfig(BaseImageEditConfig): headers: dict, model: str, api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: final_api_key: Optional[str] = api_key or get_secret_str("GEMINI_API_KEY") if not final_api_key: diff --git a/litellm/llms/litellm_proxy/image_edit/transformation.py b/litellm/llms/litellm_proxy/image_edit/transformation.py index 5f5e2bdb24..79cd6e15c6 100644 --- a/litellm/llms/litellm_proxy/image_edit/transformation.py +++ b/litellm/llms/litellm_proxy/image_edit/transformation.py @@ -8,7 +8,12 @@ class LiteLLMProxyImageEditConfig(OpenAIImageEditConfig): """Configuration for image edit requests routed through LiteLLM Proxy.""" def validate_environment( - self, headers: dict, model: str, api_key: Optional[str] = None + self, + headers: dict, + model: str, + api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: api_key = api_key or get_secret_str("LITELLM_PROXY_API_KEY") headers.update({"Authorization": f"Bearer {api_key}"}) diff --git a/litellm/llms/openai/image_edit/transformation.py b/litellm/llms/openai/image_edit/transformation.py index 6917e8d799..9c0daca802 100644 --- a/litellm/llms/openai/image_edit/transformation.py +++ b/litellm/llms/openai/image_edit/transformation.py @@ -165,6 +165,8 @@ class OpenAIImageEditConfig(BaseImageEditConfig): headers: dict, model: str, api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: api_key = ( api_key diff --git a/litellm/llms/openrouter/image_edit/transformation.py b/litellm/llms/openrouter/image_edit/transformation.py index fcf066dd5a..0d96b62425 100644 --- a/litellm/llms/openrouter/image_edit/transformation.py +++ b/litellm/llms/openrouter/image_edit/transformation.py @@ -116,6 +116,8 @@ class OpenRouterImageEditConfig(BaseImageEditConfig): headers: dict, model: str, api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: api_key = api_key or litellm.api_key or get_secret_str("OPENROUTER_API_KEY") if not api_key: diff --git a/litellm/llms/recraft/image_edit/transformation.py b/litellm/llms/recraft/image_edit/transformation.py index 4c199bc78d..1dccd40605 100644 --- a/litellm/llms/recraft/image_edit/transformation.py +++ b/litellm/llms/recraft/image_edit/transformation.py @@ -81,6 +81,8 @@ class RecraftImageEditConfig(BaseImageEditConfig): headers: dict, model: str, api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: final_api_key: Optional[str] = api_key or get_secret_str("RECRAFT_API_KEY") if not final_api_key: diff --git a/litellm/llms/stability/image_edit/transformations.py b/litellm/llms/stability/image_edit/transformations.py index eb400a2526..522858b8c2 100644 --- a/litellm/llms/stability/image_edit/transformations.py +++ b/litellm/llms/stability/image_edit/transformations.py @@ -149,6 +149,8 @@ class StabilityImageEditConfig(BaseImageEditConfig): headers: dict, model: str, api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: """ Validate environment and set up headers for Stability AI. diff --git a/litellm/llms/vertex_ai/image_edit/vertex_imagen_transformation.py b/litellm/llms/vertex_ai/image_edit/vertex_imagen_transformation.py index 7979e0e790..11126b2a3e 100644 --- a/litellm/llms/vertex_ai/image_edit/vertex_imagen_transformation.py +++ b/litellm/llms/vertex_ai/image_edit/vertex_imagen_transformation.py @@ -103,10 +103,24 @@ class VertexAIImagenImageEditConfig(BaseImageEditConfig, VertexLLM): headers: dict, model: str, api_key: Optional[str] = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: headers = headers or {} - vertex_project = self._resolve_vertex_project() - vertex_credentials = self._resolve_vertex_credentials() + litellm_params = litellm_params or {} + + _api_base = litellm_params.get("api_base") or api_base + if _api_base is not None: + return headers + + vertex_project = ( + self.safe_get_vertex_ai_project(litellm_params) + or self._resolve_vertex_project() + ) + vertex_credentials = ( + self.safe_get_vertex_ai_credentials(litellm_params) + or self._resolve_vertex_credentials() + ) access_token, _ = self._ensure_access_token( credentials=vertex_credentials, project_id=vertex_project, diff --git a/tests/test_litellm/images/test_image_edit_utils.py b/tests/test_litellm/images/test_image_edit_utils.py index e0584afb81..186a085bdc 100644 --- a/tests/test_litellm/images/test_image_edit_utils.py +++ b/tests/test_litellm/images/test_image_edit_utils.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List +from typing import Any, Dict, List, Optional from unittest.mock import MagicMock, patch import pytest @@ -26,7 +26,12 @@ class MockImageEditConfig(BaseImageEditConfig): return "https://example.com/api" def validate_environment( - self, headers: dict, model: str, api_key: str = None + self, + headers: dict, + model: str, + api_key: str = None, + litellm_params: Optional[dict] = None, + api_base: Optional[str] = None, ) -> dict: return headers