From dc2bc65df88094f0cc46111037ec53046f81da1a 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 (cherry picked from commit b892162eb3dfc7c7d8bf24d54130ee9e794832c3) --- 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 9cbbcafb569..6007ac70a54 100644 --- a/litellm/cost_calculator.py +++ b/litellm/cost_calculator.py @@ -1503,7 +1503,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 69fb81c6d3e..7a5ca1d7eb9 100644 --- a/tests/unit/test_cost_calculator.py +++ b/tests/unit/test_cost_calculator.py @@ -10270,14 +10270,37 @@ def test_bedrock_registered_cache_prices_preserve_dynamic_threshold_rates( assert entry[1][tier_field] == (tier_override if tier_override is not None else 0.007) -@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