diff --git a/litellm/proxy/spend_tracking/spend_tracking_utils.py b/litellm/proxy/spend_tracking/spend_tracking_utils.py index a37c3ba4405..0ee807e842e 100644 --- a/litellm/proxy/spend_tracking/spend_tracking_utils.py +++ b/litellm/proxy/spend_tracking/spend_tracking_utils.py @@ -216,7 +216,7 @@ def get_spend_logs_id(call_type: str, response_obj: dict, kwargs: dict) -> str | kwargs.get("litellm_call_id"), ) resolved_id: Final = next( - (candidate for candidate in candidate_ids if isinstance(candidate, str) and candidate), None + (candidate for candidate in candidate_ids if isinstance(candidate, str) and candidate not in ("", "None")), None ) if resolved_id is not None and call_type == CallTypes.aretrieve_batch.value: return f"{resolved_id}{BATCH_COST_REQUEST_ID_SUFFIX}" diff --git a/tests/test_litellm/proxy/spend_tracking/test_spend_tracking_utils.py b/tests/test_litellm/proxy/spend_tracking/test_spend_tracking_utils.py index 6a6db5ab7fe..41ce7b1b8c9 100644 --- a/tests/test_litellm/proxy/spend_tracking/test_spend_tracking_utils.py +++ b/tests/test_litellm/proxy/spend_tracking/test_spend_tracking_utils.py @@ -3399,6 +3399,19 @@ def test_get_spend_logs_id_prefers_the_response_id_over_the_standard_logging_id( ) +def test_get_spend_logs_id_falls_back_when_the_standard_logging_id_is_none(): + ids = [ + get_spend_logs_id( + "acompletion", + {"id": None}, + {"litellm_call_id": call_id, "standard_logging_object": {"id": "None"}}, + ) + for call_id in ("call-id-1", "call-id-2") + ] + + assert ids == ["call-id-1", "call-id-2"] + + @pytest.mark.asyncio async def test_spend_log_request_id_is_the_message_id_a_bridged_streaming_caller_was_streamed(): """A streaming /v1/messages call against a non-Anthropic model is served a msg_ id the