From 965c964f5112b236a8bdb401fa101dc7be7c594d Mon Sep 17 00:00:00 2001 From: ryan-crabbe-berri Date: Tue, 2 Jun 2026 17:41:07 -0700 Subject: [PATCH] fix(router): guard retry_policy type in update_settings Mirror Router.__init__ semantics in update_settings: only assign retry_policy when it is None or a RetryPolicy (after dict coercion). Previously a non-dict, non-RetryPolicy value (e.g. a YAML typo like retry_policy: 5 flowing through /config/update) was stored verbatim, deferring the failure to request time in get_num_retries_from_retry_policy instead of being dropped at write time. --- litellm/router.py | 3 ++- .../test_router_retry_policy_update.py | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/litellm/router.py b/litellm/router.py index e256d409bb0..9d07d74a643 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -10217,7 +10217,8 @@ class Router: value = kwargs[var] if isinstance(value, dict): value = RetryPolicy(**value) - setattr(self, var, value) + if value is None or isinstance(value, RetryPolicy): + setattr(self, var, value) else: value = kwargs[var] # only run routing strategy init if it has changed diff --git a/tests/test_litellm/test_router_retry_policy_update.py b/tests/test_litellm/test_router_retry_policy_update.py index 5e061f940d7..335d224d119 100644 --- a/tests/test_litellm/test_router_retry_policy_update.py +++ b/tests/test_litellm/test_router_retry_policy_update.py @@ -114,6 +114,24 @@ def test_update_settings_accepts_retry_policy_object_unchanged(): assert router.retry_policy is policy +def test_update_settings_ignores_malformed_retry_policy(): + """A non-dict, non-``RetryPolicy`` value (e.g. a YAML typo like + ``retry_policy: 5`` reaching ``update_settings``) must not land on + ``self.retry_policy``. ``Router.__init__`` already drops such inputs; + the update path must match so a malformed config can't store garbage + that ``get_num_retries_from_retry_policy`` would only choke on at + request time.""" + router = _build_router() + + existing = RetryPolicy(BadRequestErrorRetries=4) + router.update_settings(retry_policy=existing) + assert router.retry_policy is existing + + for bad_value in (5, "RateLimitErrorRetries=7", ["BadRequestErrorRetries"]): + router.update_settings(retry_policy=bad_value) + assert router.retry_policy is existing + + def test_update_settings_get_settings_round_trip_for_retry_policy(): """``GET /get/config/callbacks`` serializes ``llm_router.get_settings()`` back to the UI. After updating, the round-trip must reflect the new