diff --git a/litellm/router_utils/fallback_event_handlers.py b/litellm/router_utils/fallback_event_handlers.py index f0edc7fc9db..891d80d785a 100644 --- a/litellm/router_utils/fallback_event_handlers.py +++ b/litellm/router_utils/fallback_event_handlers.py @@ -72,7 +72,7 @@ def get_fallback_model_group( elif list(item.keys())[0] == "*": # check generic fallback generic_fallback_idx = idx elif isinstance(item, str): - fallback_model_group = [fallbacks.pop(idx)] # returns single-item list + fallback_model_group = [item] ## if none, check for generic fallback if fallback_model_group is None: if stripped_model_fallback is not None: diff --git a/tests/test_litellm/router_utils/test_fallback_event_handlers.py b/tests/test_litellm/router_utils/test_fallback_event_handlers.py index ca647bdce55..98a34de295c 100644 --- a/tests/test_litellm/router_utils/test_fallback_event_handlers.py +++ b/tests/test_litellm/router_utils/test_fallback_event_handlers.py @@ -2,7 +2,10 @@ import json import pytest -from litellm.router_utils.fallback_event_handlers import run_async_fallback +from litellm.router_utils.fallback_event_handlers import ( + get_fallback_model_group, + run_async_fallback, +) class StreamingWrapper: @@ -137,3 +140,16 @@ async def test_run_async_fallback_skips_original_model_group(): ) assert response._hidden_params["additional_headers"]["x-litellm-attempted-fallbacks"] == 1 + + +def test_get_fallback_model_group_does_not_mutate_fallbacks(): + """A string fallback must be resolved without mutating the caller's + fallbacks list, which is the live router config shared across requests.""" + fallbacks = [{"gpt-3.5-turbo": ["claude-3-haiku"]}, "gpt-4o-mini"] + + fallback_model_group, _ = get_fallback_model_group( + fallbacks=fallbacks, model_group="unmatched-model" + ) + + assert fallback_model_group == ["gpt-4o-mini"] + assert fallbacks == [{"gpt-3.5-turbo": ["claude-3-haiku"]}, "gpt-4o-mini"]