From b892162eb3dfc7c7d8bf24d54130ee9e794832c3 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Tue, 10 Nov 2026 23:53:25 -0800 Subject: [PATCH] fix(cost): leave image search responses out of the cost error text --- litellm/cost_calculator.py | 2 +- tests/unit/test_cost_calculator.py | 33 +++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/litellm/cost_calculator.py b/litellm/cost_calculator.py index ed3768e3ba5..d549872ef90 100644 --- a/litellm/cost_calculator.py +++ b/litellm/cost_calculator.py @@ -1656,7 +1656,7 @@ def _response_time_ms_for_cost( def _model_is_none_error(completion_response_text: str, litellm_logging_obj: LitellmLoggingObject | None) -> ValueError: message: Final = "Model is None and does not exist in passed completion_response." model_call_details: Final = {} if litellm_logging_obj is None else litellm_logging_obj.model_call_details - if should_redact_message_logging(model_call_details): + if should_redact_message_logging(model_call_details) or model_call_details.get("query_image") is not None: return ValueError(message) return ValueError(f"{message} Passed completion_response={completion_response_text}, model=None") diff --git a/tests/unit/test_cost_calculator.py b/tests/unit/test_cost_calculator.py index 234bdb5014a..63d66c1c0bb 100644 --- a/tests/unit/test_cost_calculator.py +++ b/tests/unit/test_cost_calculator.py @@ -11688,14 +11688,37 @@ def test_per_call_custom_prices_keep_the_regional_and_speed_multipliers( assert response._hidden_params["response_cost"] == pytest.approx((1000 * 2e-06 + 1000 * 4e-06) * multiplier) -@pytest.mark.parametrize("message_logging_off", [True, False]) -def test_cost_failure_for_an_unpriced_response_echoes_the_response_only_with_message_logging_on( - message_logging_off: bool, monkeypatch: pytest.MonkeyPatch +@pytest.mark.parametrize( + ("message_logging_off", "query_image", "echoes_response"), + [ + (True, None, False), + (False, None, True), + (False, {"type": "base64", "media_type": "image/jpeg", "data": "cXVlcnk="}, False), + ], +) +def test_cost_failure_for_an_unpriced_response_echoes_only_a_text_search_response_with_message_logging_on( + message_logging_off: bool, + query_image: Mapping[str, str] | None, + echoes_response: bool, + monkeypatch: pytest.MonkeyPatch, ) -> None: monkeypatch.setattr(litellm, "turn_off_message_logging", message_logging_off) image_data: Final = "c2VjcmV0LWltYWdlLWJ5dGVz" + logging_obj: Final = Logging( + model="", + messages=[], + stream=False, + call_type="avector_store_search", + start_time=datetime.datetime.now(), + litellm_call_id="unpriced-search", + function_id="f", + ) + logging_obj.model_call_details["query_image"] = query_image with pytest.raises(ValueError, match="Model is None") as exc_info: - completion_cost(completion_response={"data": [{"content": [{"source": {"data": image_data}}]}]}) + completion_cost( + completion_response={"data": [{"content": [{"source": {"data": image_data}}]}]}, + litellm_logging_obj=logging_obj, + ) - assert (image_data in str(exc_info.value)) is not message_logging_off + assert (image_data in str(exc_info.value)) is echoes_response