diff --git a/litellm/litellm_core_utils/llm_cost_calc/utils.py b/litellm/litellm_core_utils/llm_cost_calc/utils.py index c968fac254e..b34c416cd40 100644 --- a/litellm/litellm_core_utils/llm_cost_calc/utils.py +++ b/litellm/litellm_core_utils/llm_cost_calc/utils.py @@ -443,7 +443,7 @@ def _apply_off_peak_pricing( off_peak_pricing falls back to the standard rate. """ off_peak: Final = model_info.get("off_peak_pricing") - if not off_peak or not _is_off_peak(off_peak, current_time): + if not isinstance(off_peak, Mapping) or not _is_off_peak(off_peak, current_time): return prompt_base_cost, completion_base_cost, cache_read_cost return ( _coerce_off_peak_rate(off_peak.get("input_cost_per_token"), prompt_base_cost), diff --git a/tests/test_litellm/litellm_core_utils/llm_cost_calc/test_llm_cost_calc_utils.py b/tests/test_litellm/litellm_core_utils/llm_cost_calc/test_llm_cost_calc_utils.py index 501a9314c90..0e1c832ebf5 100644 --- a/tests/test_litellm/litellm_core_utils/llm_cost_calc/test_llm_cost_calc_utils.py +++ b/tests/test_litellm/litellm_core_utils/llm_cost_calc/test_llm_cost_calc_utils.py @@ -648,6 +648,33 @@ def test_get_token_base_cost_applies_off_peak_pricing(): assert peak[4] == 1e-7 +def test_get_token_base_cost_non_mapping_off_peak_block_bills_standard_rates(): + """A truthy non-mapping off_peak_pricing value (a bare string or a list in + YAML) must bill standard rates rather than raising, matching how every + other malformed piece of the block behaves. + """ + from datetime import datetime, timezone + from typing import cast + + from litellm.types.utils import ModelInfo + + usage = Usage(prompt_tokens=100, completion_tokens=50, total_tokens=150) + when = datetime(2026, 1, 1, 18, 0, tzinfo=timezone.utc) + + for malformed_block in ("16:00-19:00", ["16:00-19:00"], 5e-7, True): + model_info = cast( + ModelInfo, + { + "input_cost_per_token": 1e-6, + "output_cost_per_token": 2e-6, + "off_peak_pricing": malformed_block, + }, + ) + result = _get_token_base_cost(model_info, usage, current_time=when) + assert result[0] == 1e-6 + assert result[1] == 2e-6 + + def test_get_token_base_cost_off_peak_falls_back_to_standard_when_unset(): from datetime import datetime, timezone from typing import cast