From 60a4dccd85563d0af91326274e9fbe7a50ae638b Mon Sep 17 00:00:00 2001 From: Mihidum Hettiyahandi <55163074+mihidumh@users.noreply.github.com> Date: Wed, 15 Jul 2026 08:37:25 +1000 Subject: [PATCH] fix(router): don't log 'Could not identify azure model' when the deployment name resolves from the cost map MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit get_router_model_info already falls back to resolving the azure deployment's model name against the model cost map when base_model is unset — and for deployments named after real azure models (e.g. azure/gpt-4o) that resolution returns correct max tokens and costs. The unconditional ERROR was therefore spurious for exactly the deployments that need no operator action, and on busy proxies it logs thousands of times per day per multi-deployment group. Log at debug when the fallback entry carries usable limits/costs (membership alone is not enough: Router init auto-registers every deployment name as a zeroed stub), keep the ERROR otherwise. Fixes #33172 --- litellm/router.py | 24 ++++++++- tests/test_litellm/test_router.py | 89 +++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 2 deletions(-) diff --git a/litellm/router.py b/litellm/router.py index f408d030b8b..67a16c16885 100644 --- a/litellm/router.py +++ b/litellm/router.py @@ -8524,9 +8524,29 @@ class Router: ## SET MODEL TO 'model=' - if base_model is None + not azure if custom_llm_provider == "azure" and base_model is None: - verbose_router_logger.error( - f"Could not identify azure model '{_model}'. Set azure 'base_model' for accurate max tokens, cost tracking, etc.- https://docs.litellm.ai/docs/proxy/cost_tracking#spend-tracking-for-azure-openai-models" + # the `if model is None` fallback below resolves the deployment's + # model name against the model cost map — when the name is a known + # azure key (e.g. deployment model "azure/gpt-4o"), that resolution + # gives correct max tokens / costs and there is nothing for the + # operator to fix, so don't spam an ERROR on every request. + # membership alone isn't enough: Router init auto-registers every + # deployment name into litellm.model_cost as a zeroed stub, so + # require the entry to carry usable limits/costs. + _azure_fallback_key = _model if _model.startswith("azure/") else "azure/{}".format(_model) + _fallback_entry = litellm.model_cost.get(_azure_fallback_key) or {} + _fallback_resolves = ( + _fallback_entry.get("max_input_tokens") is not None + or _fallback_entry.get("max_tokens") is not None + or (_fallback_entry.get("input_cost_per_token") or 0) > 0 ) + if _fallback_resolves: + verbose_router_logger.debug( + f"Azure deployment '{_model}' has no base_model set; using '{_azure_fallback_key}' from the model cost map for max tokens, cost tracking, etc." + ) + else: + verbose_router_logger.error( + f"Could not identify azure model '{_model}'. Set azure 'base_model' for accurate max tokens, cost tracking, etc.- https://docs.litellm.ai/docs/proxy/cost_tracking#spend-tracking-for-azure-openai-models" + ) elif custom_llm_provider != "azure": model = _model diff --git a/tests/test_litellm/test_router.py b/tests/test_litellm/test_router.py index 9c4d83ff7ea..043da3edb3d 100644 --- a/tests/test_litellm/test_router.py +++ b/tests/test_litellm/test_router.py @@ -5304,3 +5304,92 @@ class TestRouterRequestTimeoutPropagation: ) == 60 ) + + +class TestAzureBaseModelFallbackLogging: + """When an azure deployment has no base_model but its model name is a known + azure key in the cost map, get_router_model_info resolves it via the + fallback — so it must not log the per-request 'Could not identify azure + model' ERROR. The ERROR must remain for genuinely unmappable deployment + names. Issue #33172.""" + + @pytest.fixture(autouse=True) + def _use_local_model_cost_map(self, monkeypatch): + monkeypatch.setenv("LITELLM_LOCAL_MODEL_COST_MAP", "True") + original_model_cost = litellm.model_cost + litellm.model_cost = litellm.get_model_cost_map(url="") + yield + litellm.model_cost = original_model_cost + + def _router_with_azure_deployment(self, deployment_model: str): + return litellm.Router( + model_list=[ + { + "model_name": "my-group", + "litellm_params": { + "model": deployment_model, + "api_key": "fake-key", + "api_base": "https://fake.openai.azure.com", + }, + "model_info": {"id": "azure-base-model-test-id"}, + } + ] + ) + + def test_map_known_deployment_name_resolves_without_error_log(self): + router = self._router_with_azure_deployment("azure/gpt-4o") + + with patch( + "litellm.router.verbose_router_logger.error" + ) as mock_error: + model_info = router.get_router_model_info( + deployment=None, received_model_name="my-group", id="azure-base-model-test-id" + ) + + assert not any( + "Could not identify azure model" in str(call) + for call in mock_error.call_args_list + ), f"unexpected error log: {mock_error.call_args_list}" + # the fallback resolution must actually surface the map values + assert model_info["max_input_tokens"] == litellm.model_cost["azure/gpt-4o"]["max_input_tokens"] + assert model_info["input_cost_per_token"] == litellm.model_cost["azure/gpt-4o"]["input_cost_per_token"] + + def test_unmappable_deployment_name_still_logs_error(self): + router = self._router_with_azure_deployment("azure/my-custom-deployment-name") + + with patch( + "litellm.router.verbose_router_logger.error" + ) as mock_error: + model_info = router.get_router_model_info( + deployment=None, received_model_name="my-group", id="azure-base-model-test-id" + ) + + assert any( + "Could not identify azure model" in str(call) + for call in mock_error.call_args_list + ), "expected the error log for an unmappable azure deployment name" + # unmappable names resolve to a zeroed stub — unchanged behavior + assert model_info.get("max_input_tokens") is None + + def test_explicit_base_model_still_wins(self): + router = litellm.Router( + model_list=[ + { + "model_name": "my-group", + "litellm_params": { + "model": "azure/some-deployment", + "api_key": "fake-key", + "api_base": "https://fake.openai.azure.com", + }, + "model_info": { + "id": "azure-base-model-test-id", + "base_model": "azure/gpt-4o-mini", + }, + } + ] + ) + + model_info = router.get_router_model_info( + deployment=None, received_model_name="my-group", id="azure-base-model-test-id" + ) + assert model_info["max_input_tokens"] == litellm.model_cost["azure/gpt-4o-mini"]["max_input_tokens"]