From 7abed5a14c4655dc41bc1984347685db8c67c08b Mon Sep 17 00:00:00 2001 From: Deepanshu Date: Mon, 24 Aug 2026 16:21:18 -0400 Subject: [PATCH] fix(rate-limiting): reject non-positive tag rate limits at config load limit <= 0 makes the atomic requests/concurrency check reject every admission and the read-only tokens/dollars check never admit, the same silent always-block failure mode already guarded against for a negative-infinity limit. Almost certainly a config typo rather than an intended policy, so reject it at config load time like NaN/infinity. Found by Cursor Bugbot on PR #36541. --- litellm/types/router.py | 7 +++++++ .../test_model_based_tag_rate_limits_hook.py | 15 +++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/litellm/types/router.py b/litellm/types/router.py index cc079a50c33..7e0a617ef65 100644 --- a/litellm/types/router.py +++ b/litellm/types/router.py @@ -238,6 +238,13 @@ class TagRateLimitEntry(BaseModel): "limit must be finite -- positive infinity makes admission never reject (current + increment " "> limit is always false), negative infinity makes it always reject every tagged request" ) + if self.limit <= 0: + raise ValueError( + "limit must be a positive number -- zero or negative makes the atomic requests/concurrency " + "check (current + increment > limit) reject every admission and the read-only tokens/dollars " + "check (current < limit) never admit, silently blocking all matching traffic instead of the " + "likely intended config" + ) return self @model_validator(mode="after") diff --git a/tests/test_litellm/proxy/hooks/test_model_based_tag_rate_limits_hook.py b/tests/test_litellm/proxy/hooks/test_model_based_tag_rate_limits_hook.py index 6dc7da61c56..4f68ecae819 100644 --- a/tests/test_litellm/proxy/hooks/test_model_based_tag_rate_limits_hook.py +++ b/tests/test_litellm/proxy/hooks/test_model_based_tag_rate_limits_hook.py @@ -288,6 +288,21 @@ def test_tag_rate_limit_entry_rejects_infinite_limit(): TagRateLimitEntry(name="n", limit=float("-inf"), period_seconds=60) +def test_tag_rate_limit_entry_rejects_zero_or_negative_limit(): + """ + A limit of 0 (or negative) makes the atomic requests/concurrency check + (current + increment > limit) reject every admission and the read-only + tokens/dollars check (current < limit) never admit, same silent + always-reject-everything failure mode as a negative-infinity limit -- + almost certainly a config typo, not an intentional "block everything" + policy, so reject it at config load time instead. + """ + with pytest.raises(ValidationError, match="limit must be a positive number"): + TagRateLimitEntry(name="n", limit=0, period_seconds=60) + with pytest.raises(ValidationError, match="limit must be a positive number"): + TagRateLimitEntry(name="n", limit=-1, period_seconds=60) + + # --------------------------------------------------------------------------- # TagRateLimitEntry -- period_seconds validation # ---------------------------------------------------------------------------