From 12da4039b93d6634083cb96856755048c4d3cc2b Mon Sep 17 00:00:00 2001 From: Max Falk Date: Sat, 20 Sep 2025 00:21:02 +0200 Subject: [PATCH] fix: Prevent AttributeError for _get_tags_from_request_kwargs (#14735) * fix: avoid NoneType AttributeError when extracting tags I've been running into this error: ``` 21:47:08 - LiteLLM:ERROR: litellm_logging.py:2396 - LiteLLM.LoggingError: [Non-Blocking] Exception occurred while success logging Traceback (most recent call last): File "/usr/lib/python3.13/site-packages/litellm/litellm_core_utils/litellm_logging.py", line 2312, in async_success_handler await callback.async_log_success_event( ...<6 lines>... ) File "/usr/lib/python3.13/site-packages/litellm/router_strategy/budget_limiter.py", line 396, in async_log_success_event request_tags = _get_tags_from_request_kwargs(kwargs) File "/usr/lib/python3.13/site-packages/litellm/router_strategy/tag_based_routing.py", line 144, in _get_tags_from_request_kwargs return _metadata.get("tags", []) ^^^^^^^^^^^^^ AttributeError: 'NoneType' object has no attribute 'get' ``` This makes the function more resilient without resorting to try catch. * add tests Signed-off-by: Max Falk --------- Signed-off-by: Max Falk --- litellm/router_strategy/tag_based_routing.py | 6 +-- .../test_router_tag_routing.py | 48 ++++++++++++++++++- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/litellm/router_strategy/tag_based_routing.py b/litellm/router_strategy/tag_based_routing.py index 8094b5d86ac..1384c7aea00 100644 --- a/litellm/router_strategy/tag_based_routing.py +++ b/litellm/router_strategy/tag_based_routing.py @@ -136,10 +136,10 @@ def _get_tags_from_request_kwargs( if request_kwargs is None: return [] if metadata_variable_name in request_kwargs: - metadata = request_kwargs[metadata_variable_name] + metadata = request_kwargs[metadata_variable_name] or {} return metadata.get("tags", []) elif "litellm_params" in request_kwargs: - litellm_params = request_kwargs["litellm_params"] - _metadata = litellm_params.get(metadata_variable_name, {}) + litellm_params = request_kwargs["litellm_params"] or {} + _metadata = litellm_params.get(metadata_variable_name, {}) or {} return _metadata.get("tags", []) return [] diff --git a/tests/test_litellm/router_strategy/test_router_tag_routing.py b/tests/test_litellm/router_strategy/test_router_tag_routing.py index e78a16c6212..a3e722eeb85 100644 --- a/tests/test_litellm/router_strategy/test_router_tag_routing.py +++ b/tests/test_litellm/router_strategy/test_router_tag_routing.py @@ -385,4 +385,50 @@ async def test_router_free_paid_tier_with_responses_api(): response_extra_info = response._hidden_params print("response_extra_info: ", response_extra_info) - assert response_extra_info["model_id"] == "very-expensive-model" \ No newline at end of file + assert response_extra_info["model_id"] == "very-expensive-model" + +def test_get_tags_from_request_kwargs_none(): + from litellm.router_strategy.tag_based_routing import _get_tags_from_request_kwargs + + # None request kwargs should safely return empty list + assert _get_tags_from_request_kwargs(None) == [] + + +def test_get_tags_from_request_kwargs_various_inputs(): + from litellm.router_strategy.tag_based_routing import _get_tags_from_request_kwargs + + # Direct "metadata" path + assert _get_tags_from_request_kwargs({"metadata": {"tags": ["free"]}}) == ["free"] + assert _get_tags_from_request_kwargs({"metadata": {"tags": []}}) == [] + assert _get_tags_from_request_kwargs({"metadata": {"tags": None}}) == [] + assert _get_tags_from_request_kwargs({"metadata": {}}) == [] + assert _get_tags_from_request_kwargs({"metadata": None}) == [] + + # Indirect via "litellm_params" - metadata inside + assert ( + _get_tags_from_request_kwargs( + {"litellm_params": {"metadata": {"tags": ["paid"]}}} + ) + == ["paid"] + ) + assert _get_tags_from_request_kwargs({"litellm_params": {"metadata": None}}) == [] + assert _get_tags_from_request_kwargs({"litellm_params": {}}) == [] + + # Alternate metadata variable name: "litellm_metadata" + assert ( + _get_tags_from_request_kwargs( + {"litellm_metadata": {"tags": ["alt"]}}, + metadata_variable_name="litellm_metadata", + ) + == ["alt"] + ) + assert ( + _get_tags_from_request_kwargs( + {"litellm_params": {"litellm_metadata": {"tags": ["nested-alt"]}}}, + metadata_variable_name="litellm_metadata", + ) + == ["nested-alt"] + ) + + # No relevant keys present + assert _get_tags_from_request_kwargs({"foo": "bar"}) == [] \ No newline at end of file