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