From 23b4a39526eacb544244da801864c798cbd2d9f6 Mon Sep 17 00:00:00 2001 From: Karlla Nascimento <89461448+karllasnascimento@users.noreply.github.com> Date: Sun, 29 Mar 2026 22:46:27 -0300 Subject: [PATCH] fix: snapshot kwargs before fallback loop to prevent cross-iteration mutation Address Greptile review feedback: the previous deep copy was taken from the current (potentially mutated) kwargs. Now snapshot base_kwargs before the loop and copy from it each iteration, matching the pattern in fallback_utils.py. Also move the import inside the function to avoid cyclic import (CodeQL). --- litellm/router_utils/fallback_event_handlers.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/litellm/router_utils/fallback_event_handlers.py b/litellm/router_utils/fallback_event_handlers.py index 39254509c93..3ec96dc040c 100644 --- a/litellm/router_utils/fallback_event_handlers.py +++ b/litellm/router_utils/fallback_event_handlers.py @@ -8,7 +8,6 @@ from litellm.router_utils.add_retry_fallback_headers import ( add_fallback_headers_to_response, ) from litellm.types.router import LiteLLMParamsTypedDict -from litellm.litellm_core_utils.core_helpers import safe_deep_copy if TYPE_CHECKING: from litellm.router import Router as _Router @@ -120,15 +119,21 @@ async def run_async_fallback( error_from_fallbacks = original_exception + # Snapshot original kwargs before the fallback loop so that each + # iteration starts from a clean, unmutated copy. + from litellm.litellm_core_utils.core_helpers import safe_deep_copy + + base_kwargs = safe_deep_copy(kwargs) + for mg in fallback_model_group: if mg == original_model_group: continue try: - # Deep copy kwargs to prevent mutations from one provider - # (e.g., Bedrock popping 'tools' from optional_params) - # from corrupting kwargs for subsequent fallback providers. - # See: https://github.com/BerriAI/litellm/issues/24764 - kwargs = safe_deep_copy(kwargs) + # Each iteration gets a fresh copy from the clean original + # to prevent provider-specific mutations (e.g., Bedrock + # popping 'tools' from optional_params) from corrupting + # subsequent fallback calls. See: #24764 + kwargs = safe_deep_copy(base_kwargs) # LOGGING kwargs = litellm_router.log_retry(kwargs=kwargs, e=original_exception)