fix(router): use .get() for 'hidden' and 'model' keys in dict-style model_group_alias entries

RouterModelGroupAliasItem is a TypedDict with required fields 'model'
and 'hidden', but TypedDict is a type-hint only — Python does not
validate or inject keys at runtime.  Any user whose config omits the
'hidden' key (natural, since it is only needed to hide a group) gets a
plain dict without it:

    model_group_alias:
      'gpt-4-alias': {model: gpt-3.5-turbo}   # no hidden key

This caused a KeyError on every request because:
  - get_model_group_info() is called by set_response_headers on every
    router completion (confirmed by source comment)
  - get_model_list_from_model_alias() is called during Router.__init__
    via set_model_list -> get_model_names

Both call sites used item['hidden'] and item['model'] directly.

Fix: switch to item.get('hidden') and item.get('model', '') in both
locations.  item.get('hidden') returns None when the key is absent,
and None is not True, so the visibility logic is preserved correctly.

Adds regression test covering three cases:
  - dict alias without 'hidden' key (no KeyError, returns info)
  - dict alias with hidden=True (returns None)
  - dict alias with hidden=False (returns info)
This commit is contained in:
Dantuluri Surya Narayana Raju 2026-05-17 20:18:34 +05:30
parent cf9b5e4fa7
commit ee71d69db0
2 changed files with 54 additions and 4 deletions

View file

@ -8697,10 +8697,10 @@ class Router:
if isinstance(item, str):
_router_model_group = item
elif isinstance(item, dict):
if item["hidden"] is True:
if item.get("hidden") is True:
return None
else:
_router_model_group = item["model"]
_router_model_group = item.get("model", "")
else:
return None
@ -9299,10 +9299,10 @@ class Router:
_router_model_name: str = model_value
elif isinstance(model_value, dict):
_model_value = RouterModelGroupAliasItem(**model_value) # type: ignore
if _model_value["hidden"] is True:
if _model_value.get("hidden") is True:
continue
else:
_router_model_name = _model_value["model"]
_router_model_name = _model_value.get("model", "")
else:
continue

View file

@ -977,6 +977,56 @@ def test_update_settings(model_list):
assert router.allowed_fails == 20
def test_get_model_group_info_alias_dict_without_hidden_key(model_list):
"""Regression test: get_model_group_info must not raise KeyError when a
dict-style model_group_alias entry omits the 'hidden' key.
RouterModelGroupAliasItem declares 'hidden: bool' as a TypedDict field, but
TypedDict is a type-hint only — Python does NOT inject default values at
runtime. Any user who writes:
model_group_alias:
"gpt-4-alias": {"model": "gpt-3.5-turbo"}
gets a plain dict without 'hidden', causing item["hidden"] to raise
KeyError on every request (via set_response_headers -> get_model_group_info).
"""
alias_model_list = list(model_list) + [
{
"model_name": "gpt-3.5-turbo",
"litellm_params": {"model": "openai/gpt-3.5-turbo", "api_key": "sk-fake"},
}
]
router = Router(
model_list=alias_model_list,
model_group_alias={
"gpt-4-alias": {"model": "gpt-3.5-turbo"},
},
)
# Must not raise KeyError — 'hidden' key is absent from the alias dict
result = router.get_model_group_info(model_group="gpt-4-alias")
assert result is not None
# Alias with hidden=True must still return None
router2 = Router(
model_list=alias_model_list,
model_group_alias={
"secret-alias": {"model": "gpt-3.5-turbo", "hidden": True},
},
)
assert router2.get_model_group_info(model_group="secret-alias") is None
# Alias with hidden=False (explicit) must return info
router3 = Router(
model_list=alias_model_list,
model_group_alias={
"visible-alias": {"model": "gpt-3.5-turbo", "hidden": False},
},
)
assert router3.get_model_group_info(model_group="visible-alias") is not None
def test_common_checks_available_deployment(model_list):
"""Test if the 'common_checks_available_deployment' function is working correctly"""
router = Router(model_list=model_list)