From 59a48b3b898f49fd575a3d867f83e081208d71b3 Mon Sep 17 00:00:00 2001 From: Surender Gulia Date: Wed, 28 Oct 2026 11:25:10 +0000 Subject: [PATCH] fix(logging): fallback to bare model name on provider mismatch in model cost lookup (closes #47675) --- litellm/litellm_core_utils/litellm_logging.py | 33 +++++++++--- .../test_model_cost_information.py | 52 +++++++++++++++++++ 2 files changed, 77 insertions(+), 8 deletions(-) create mode 100644 tests/unit/litellm_core_utils/test_model_cost_information.py diff --git a/litellm/litellm_core_utils/litellm_logging.py b/litellm/litellm_core_utils/litellm_logging.py index 48e8a44b9a4..f6c10b27230 100644 --- a/litellm/litellm_core_utils/litellm_logging.py +++ b/litellm/litellm_core_utils/litellm_logging.py @@ -6757,7 +6757,7 @@ class StandardLoggingPayloadSetup: model_cost_information = StandardLoggingModelInformation(model_map_key="", model_map_value=None) else: try: - _model_cost_information: Final = litellm.get_model_info( + _model_cost_information = litellm.get_model_info( model=pricing_model_name or model_cost_name, custom_llm_provider=custom_llm_provider, api_base=api_base, @@ -6767,13 +6767,30 @@ class StandardLoggingPayloadSetup: model_map_value=_model_cost_information, ) except Exception: - verbose_logger.debug( # keep in debug otherwise it will trigger on every call - "Model=%s is not mapped in model cost map. Defaulting to None model_cost_information for standard_logging_payload", - model_cost_name, - ) - model_cost_information = StandardLoggingModelInformation( - model_map_key=model_cost_name, model_map_value=None - ) + # Fallback: if provider mismatch lookup fails, try bare model name + _model_cost_information = None + if custom_llm_provider is not None: + try: + _model_cost_information = litellm.get_model_info( + model=pricing_model_name or model_cost_name, + api_base=api_base, + ) + except Exception: + _model_cost_information = None + + if _model_cost_information is not None: + model_cost_information = StandardLoggingModelInformation( + model_map_key=model_cost_name, + model_map_value=_model_cost_information, + ) + else: + verbose_logger.debug( # keep in debug otherwise it will trigger on every call + "Model=%s is not mapped in model cost map. Defaulting to None model_cost_information for standard_logging_payload", + model_cost_name, + ) + model_cost_information = StandardLoggingModelInformation( + model_map_key=model_cost_name, model_map_value=None + ) return model_cost_information @staticmethod diff --git a/tests/unit/litellm_core_utils/test_model_cost_information.py b/tests/unit/litellm_core_utils/test_model_cost_information.py new file mode 100644 index 00000000000..cd607615752 --- /dev/null +++ b/tests/unit/litellm_core_utils/test_model_cost_information.py @@ -0,0 +1,52 @@ +""" +Regression test for Issue #47675: +Verifies that get_model_cost_information falls back to bare model name lookup +when deployment custom_llm_provider does not match the provider key in model pricing map. +""" +import pytest +import litellm +from litellm.litellm_core_utils.litellm_logging import StandardLoggingPayloadSetup +from litellm.types.utils import ModelResponse + + +def test_cross_key_provider_mismatch_fallback(): + """ + Test that when custom_llm_provider='anthropic' is used with a model priced under + another provider (e.g., 'tencent/deepseek-v4.1-flash'), the fallback populates + model_map_value instead of silently returning None ($0 spend). + """ + setup = StandardLoggingPayloadSetup() + model = "tencent/deepseek-v4.1-flash" + mock_response = ModelResponse(model=model) + + info = setup.get_model_cost_information( + base_model=model, + custom_pricing=False, + custom_llm_provider="anthropic", + init_response_obj=mock_response, + ) + + assert info.get("model_map_key") == model + assert info.get("model_map_value") is not None + assert info["model_map_value"].get("litellm_provider") == "tencent" + assert info["model_map_value"].get("input_cost_per_token") == 3e-07 + + +def test_unmapped_model_safely_returns_none(): + """ + Test that an unknown model that does not exist in the pricing map + safely returns model_map_value=None without raising unhandled exceptions. + """ + setup = StandardLoggingPayloadSetup() + fake_model = "fake_provider/completely_non_existent_model_xyz" + mock_response = ModelResponse(model=fake_model) + + info = setup.get_model_cost_information( + base_model=fake_model, + custom_pricing=False, + custom_llm_provider="anthropic", + init_response_obj=mock_response, + ) + + assert info.get("model_map_key") == fake_model + assert info.get("model_map_value") is None