From 3b0f8287f4a5d0df9aa58fc87d45c3ef977112fb Mon Sep 17 00:00:00 2001 From: Deepanshu Date: Mon, 17 Aug 2026 14:00:59 -0400 Subject: [PATCH] fix(rate-limiting): dedupe a deployment's own repeated entry before counting declarations A deployment declaring the identical concurrency_limits entry twice appended its own id twice, inflating len(declaring_ids) past total_deployments. That made is_chain_wide false for an entry every deployment actually agreed on, and a non-chain-wide concurrency entry is silently dropped entirely rather than degraded -- disabling enforcement instead of just scoping it. --- litellm/proxy/hooks/tag_rate_limiter.py | 9 +++++- .../proxy/hooks/test_tag_rate_limiter.py | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/litellm/proxy/hooks/tag_rate_limiter.py b/litellm/proxy/hooks/tag_rate_limiter.py index 01876511b03..5c05caca04c 100644 --- a/litellm/proxy/hooks/tag_rate_limiter.py +++ b/litellm/proxy/hooks/tag_rate_limiter.py @@ -280,7 +280,14 @@ def _build_group_limits(deployments: Sequence[Mapping[str, object]], unit: _Limi for entry in _entries_for_unit(deployment, unit): signature = (entry.tag_id, entry.name, entry.limit, entry.period_seconds, entry.scope_by_key_hash) ids_for_signature = declaring_ids_by_signature.setdefault(signature, []) # mutable-ok: see comment above - ids_for_signature.append(dep_id) + # One deployment declaring the identical entry twice (a config + # duplicate) must count once, or len(declaring_ids) inflates past + # total_deployments below, making is_chain_wide false for an + # entry every deployment actually agrees on -- for concurrency + # that silently drops the entry entirely (see the docstring + # above), disabling enforcement rather than degrading it. + if dep_id not in ids_for_signature: + ids_for_signature.append(dep_id) # mutable-ok: see comment above representative_entry_by_signature.setdefault(signature, entry) # mutable-ok: see comment above distinct_signature_count_by_name: Final[Mapping[tuple[str, str], int]] = MappingProxyType( diff --git a/tests/test_litellm/proxy/hooks/test_tag_rate_limiter.py b/tests/test_litellm/proxy/hooks/test_tag_rate_limiter.py index dd547d88a4b..494853e082a 100644 --- a/tests/test_litellm/proxy/hooks/test_tag_rate_limiter.py +++ b/tests/test_litellm/proxy/hooks/test_tag_rate_limiter.py @@ -1510,6 +1510,34 @@ def test_build_limits_index_preserves_key_ttl_seconds_and_max_in_memory_cache_si assert configured[0].entry.max_in_memory_cache_size == 500 +def test_build_limits_index_treats_a_duplicated_entry_on_one_deployment_as_chain_wide(): + """ + Regression test: a single deployment declaring the identical + concurrency_limits entry twice (a config duplicate) used to append that + deployment's id twice, inflating len(declaring_ids) past + total_deployments. That made is_chain_wide false even though every + deployment (there's only one) actually agreed on the entry, and for + concurrency a non-chain-wide entry is silently dropped entirely -- + disabling enforcement rather than degrading it. + """ + deployment = _deployment( + "grp", + "dep-1", + { + "concurrency_limits": { + "limits": [ + {"name": "inflight", "tag_id": "end_user_id", "limit": 5, "period_seconds": 300}, + {"name": "inflight", "tag_id": "end_user_id", "limit": 5, "period_seconds": 300}, + ] + } + }, + ) + index = _build_limits_index([deployment]) + configured = index.resolve("grp", team_id=None) + assert len(configured) == 1 + assert configured[0].deployment_scope is None # chain-wide, not dropped + + def test_build_limits_index_keeps_different_teams_same_alias_separate(): """ `team_public_model_name` is only unique per team: Router itself lets two