From c49f1ba30d5077d60c2b72517d46dcacb131b99c Mon Sep 17 00:00:00 2001 From: mikemikimike <13286568797@163.com> Date: Wed, 19 Aug 2026 11:03:18 +0800 Subject: [PATCH] fix(router): persist max fallback setting updates --- litellm/router.py | 3 +++ litellm/types/router.py | 1 + .../test_router_retry_policy_update.py | 15 +++++++++++++++ 3 files changed, 19 insertions(+) diff --git a/litellm/router.py b/litellm/router.py index 045fd32847c..95c1ceaf472 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -10456,6 +10456,7 @@ class Router: "allowed_fails", "cooldown_time", "num_retries", + "max_fallbacks", "timeout", "max_retries", "retry_after", @@ -10494,6 +10495,7 @@ class Router: "allowed_fails", "cooldown_time", "num_retries", + "max_fallbacks", "timeout", "max_retries", "retry_after", @@ -10510,6 +10512,7 @@ class Router: _int_settings: Final = [ "timeout", "num_retries", + "max_fallbacks", "retry_after", "allowed_fails", "cooldown_time", diff --git a/litellm/types/router.py b/litellm/types/router.py index 99a4603ae49..2136fb3132e 100644 --- a/litellm/types/router.py +++ b/litellm/types/router.py @@ -117,6 +117,7 @@ class UpdateRouterConfig(BaseModel): allowed_fails: int | None = None cooldown_time: float | None = None num_retries: int | None = None + max_fallbacks: int | None = None timeout: float | None = None max_retries: int | None = None retry_after: float | None = None diff --git a/tests/test_litellm/test_router_retry_policy_update.py b/tests/test_litellm/test_router_retry_policy_update.py index 1b98b8c1ae8..ccf378e0650 100644 --- a/tests/test_litellm/test_router_retry_policy_update.py +++ b/tests/test_litellm/test_router_retry_policy_update.py @@ -44,6 +44,13 @@ def test_update_router_config_exposes_retry_policy_field(): assert "retry_policy" in UpdateRouterConfig.model_fields +def test_update_router_config_preserves_max_fallbacks(): + value = 10 + config = UpdateRouterConfig(max_fallbacks=value) + + assert config.model_dump(exclude_none=True)["max_fallbacks"] == value + + def test_update_router_config_accepts_retry_policy_payload(): """The exact payload the Admin UI Model Retry Settings tab sends must round-trip through the schema's ``dict(exclude_none=True)`` form, since @@ -122,6 +129,14 @@ def test_update_settings_persists_retry_policy_dict(): assert router.retry_policy.TimeoutErrorRetries == 3 +def test_update_settings_applies_max_fallbacks(): + router = _build_router() + + router.update_settings(max_fallbacks=10) + + assert router.max_fallbacks == 10 + + def test_update_settings_accepts_retry_policy_object_unchanged(): """A pre-built ``RetryPolicy`` instance must pass through verbatim so callers that already constructed one (e.g. tests or programmatic