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 <gmdfalk@gmail.com>

---------

Signed-off-by: Max Falk <gmdfalk@gmail.com>
This commit is contained in:
Max Falk 2025-09-20 00:21:02 +02:00 committed by GitHub
parent dd89bae2ff
commit 12da4039b9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 50 additions and 4 deletions

View file

@ -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 []

View file

@ -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"
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"}) == []