fix(router): guard update_settings against null default_litellm_params/optional_pre_call_checks

_add_router_settings_from_db_config merges config.yaml router_settings with
the DB router_settings row and calls update_settings(**combined) directly,
without going through UpdateRouterConfig's exclude_none filtering. An
explicit `default_litellm_params: null` or `optional_pre_call_checks: null`
in either source therefore reached the new elif branches verbatim:
`{**dict, **None}` and iterating `None` both raise TypeError, crashing
proxy startup / config sync.
This commit is contained in:
Krrish Dholakia 2026-07-13 18:37:46 -07:00
parent 6eff7264c0
commit dcfdc6dbb0
2 changed files with 24 additions and 4 deletions

View file

@ -9757,11 +9757,13 @@ class Router:
if value is None or isinstance(value, RetryPolicy):
setattr(self, var, value)
elif var == "default_litellm_params":
self.default_litellm_params = {**self.default_litellm_params, **kwargs[var]}
if kwargs[var] is not None:
self.default_litellm_params = {**self.default_litellm_params, **kwargs[var]}
elif var == "optional_pre_call_checks":
new_checks = [check for check in kwargs[var] if check not in self.optional_pre_call_checks]
if new_checks:
self.add_optional_pre_call_checks(new_checks)
if kwargs[var] is not None:
new_checks = [check for check in kwargs[var] if check not in self.optional_pre_call_checks]
if new_checks:
self.add_optional_pre_call_checks(new_checks)
else:
value = kwargs[var]
# only run routing strategy init if it has changed

View file

@ -5401,3 +5401,21 @@ def test_get_settings_includes_default_litellm_params_and_optional_pre_call_chec
assert settings["optional_pre_call_checks"] == ["prompt_caching"]
assert "default_litellm_params" in settings
assert isinstance(settings["default_litellm_params"], dict)
def test_update_settings_tolerates_null_default_litellm_params_and_optional_pre_call_checks():
"""
Regression test: `_add_router_settings_from_db_config` calls
`update_settings(**combined_router_settings)` with the raw dict merged from
config.yaml and the DB router_settings row - neither is filtered through
`UpdateRouterConfig(exclude_none=True)` first, so an explicit
`default_litellm_params: null` / `optional_pre_call_checks: null` in either
source reaches update_settings verbatim. `{**dict, **None}` and iterating
`None` both raise TypeError, which would crash proxy startup / config sync.
"""
router = _make_router_for_settings_tests(timeout=42)
router.update_settings(default_litellm_params=None, optional_pre_call_checks=None)
assert router.default_litellm_params["timeout"] == 42
assert router.optional_pre_call_checks == []