fix(rate-limiting): read success-event tags from the resolved metadata bucket, not raw kwargs

Bugbot finding: async_log_success_event passed raw kwargs (Logging.model_call_details)
to _get_tags_from_request_kwargs, which checks a top-level key matching
metadata_variable_name before falling back to kwargs["litellm_params"]. Some
call paths populate that top-level key present but None, so it won it over
the real, populated dict nested under litellm_params, silently dropping
token/dollar accounting for those routes. key_hash/key_alias/order_tags_for_identity_resolution
already read from litellm_params_for_metadata; tag extraction now does too.
Regression test confirmed to fail on the pre-fix code.
This commit is contained in:
Deepanshu 2026-08-27 20:15:03 -04:00
parent 1fe4b6699d
commit 63299d9df6
2 changed files with 45 additions and 1 deletions

View file

@ -725,7 +725,7 @@ class _PROXY_GlobalTagRateLimitsHook( # pyright: ignore[reportUnusedClass] # o
key_alias: Final = _extract_key_alias(litellm_params_for_metadata, metadata_variable_name)
tags: Final = _order_tags_for_identity_resolution(
_get_tags_from_request_kwargs(kwargs, metadata_variable_name=metadata_variable_name),
_get_tags_from_request_kwargs(litellm_params_for_metadata, metadata_variable_name=metadata_variable_name),
litellm_params_for_metadata,
metadata_variable_name,
)

View file

@ -1181,6 +1181,50 @@ async def test_log_success_event_accounts_when_litellm_params_carries_a_null_lit
)
@pytest.mark.asyncio
async def test_log_success_event_reads_tags_when_top_level_kwargs_carries_a_null_metadata_key(
time_controller, monkeypatch
):
"""
Bugbot finding: some call paths populate a top-level "metadata" (or
"litellm_metadata") key on kwargs (Logging.model_call_details) set to
None, alongside the real, populated dict nested under
kwargs["litellm_params"]. _get_tags_from_request_kwargs checks the
top-level key first; passing it raw kwargs made a present-but-None
top-level key win, reading no tags at all even though
metadata_variable_name correctly resolved to "metadata".
"""
monkeypatch.setattr(
litellm,
"global_tag_rate_limits",
{
"dollar_limits": {
"limits": [{"name": "daily_spend", "tag_id": "end_user_id", "limit": 10.0, "period_seconds": 86400}]
}
},
)
hook = _make_hook(time_controller)
kwargs = {
"litellm_call_id": "call-1",
"metadata": None,
"litellm_params": {
"metadata": {"tags": ["end_user_id:u1"], "user_api_key": "hash"},
},
"standard_logging_object": {"total_tokens": 0, "response_cost": 12.0},
}
await hook.async_log_success_event(kwargs=kwargs, response_obj=None, start_time=0, end_time=0)
await asyncio.sleep(0)
with pytest.raises(ProxyRateLimitError):
await hook.async_pre_call_hook(
user_api_key_dict=_key(),
cache=DualCache(),
data=_data(["end_user_id:u1"], call_id="call-2"),
call_type="completion",
)
@pytest.mark.asyncio
async def test_dollar_limit_respects_apply_to_key_alias_at_accounting_time(time_controller, monkeypatch):
"""The entry only applies to `premium-key`; a non-listed key's spend must