diff --git a/litellm/router.py b/litellm/router.py index fc888495e99..ccb1180d348 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -12469,7 +12469,27 @@ class Router: else: model_info_name = model - model_info: Final = litellm.get_model_info(model=model_info_name) + try: + model_info: Final = litellm.get_model_info(model=model_info_name) + except Exception as e: + if e.__class__.__name__ == "ModelNotMappedError" or "not mapped" in str(e).lower(): + verbose_router_logger.warning( + "Model '%s' not mapped in model_cost; returning fallback info for compaction/budget checks: %s", + model_info_name, + e, + ) + fallback: Final[ModelMapInfo] = { + "key": model_info_name, + "max_tokens": None, + "max_input_tokens": None, + "max_output_tokens": None, + "input_cost_per_token": 0, + "output_cost_per_token": 0, + "litellm_provider": custom_llm_provider or "", + "mode": "chat", + } + return fallback + raise if model_info is None: return model_info diff --git a/tests/unit/test_router_model_not_mapped_fallback.py b/tests/unit/test_router_model_not_mapped_fallback.py new file mode 100644 index 00000000000..95161dc879c --- /dev/null +++ b/tests/unit/test_router_model_not_mapped_fallback.py @@ -0,0 +1,48 @@ +from typing import Final +from unittest.mock import patch + +import pytest + +import litellm +from litellm.exceptions import ModelNotMappedError +from litellm.router import Router + + +def test_get_router_model_info_returns_fallback_on_model_not_mapped_error() -> None: + router: Final = Router( + model_list=[ + { + "model_name": "mcp-stdio-group", + "litellm_params": { + "model": "openai/unmapped-mcp-stdio-model", + "api_key": "test-key", + }, + } + ] + ) + + with patch.object( + litellm, + "get_model_info", + side_effect=ModelNotMappedError(message="Model 'unmapped-mcp-stdio-model' is not mapped", model="unmapped-mcp-stdio-model"), + ): + info: Final = router.get_router_model_info(model="mcp-stdio-group") + + assert info is not None + assert info["max_tokens"] is None + assert info["max_input_tokens"] is None + assert info["max_output_tokens"] is None + assert info["input_cost_per_token"] == 0 + assert info["output_cost_per_token"] == 0 + assert info["litellm_provider"] == "openai" + assert info["mode"] == "chat" + + +def test_get_router_model_info_reraises_unrelated_exceptions() -> None: + router: Final = Router(model_list=[]) + + with ( + patch.object(litellm, "get_model_info", side_effect=RuntimeError("unexpected failure")), + pytest.raises(RuntimeError, match="unexpected failure"), + ): + router.get_router_model_info(model="any-model")