From 7b8d48782bc285d3b1b905751e0234914f2ba91f Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Wed, 26 Aug 2026 13:25:23 -0700 Subject: [PATCH 1/2] fix(caching): require the namespace delimiter when checking already-namespaced redis keys --- litellm/caching/redis_cache.py | 2 +- .../test_litellm/caching/test_redis_cache.py | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/litellm/caching/redis_cache.py b/litellm/caching/redis_cache.py index 68cad24ee96..d12f2066cf1 100644 --- a/litellm/caching/redis_cache.py +++ b/litellm/caching/redis_cache.py @@ -435,7 +435,7 @@ class RedisCache(BaseCache): """ if key is None: return key - if self.namespace is not None and not key.startswith(self.namespace): + if self.namespace is not None and not key.startswith(self.namespace + ":"): key = self.namespace + ":" + key return key diff --git a/tests/test_litellm/caching/test_redis_cache.py b/tests/test_litellm/caching/test_redis_cache.py index decf59130fe..915e5eac45d 100644 --- a/tests/test_litellm/caching/test_redis_cache.py +++ b/tests/test_litellm/caching/test_redis_cache.py @@ -17,6 +17,30 @@ def redis_no_ping(): yield +@pytest.mark.parametrize( + ("namespace", "key", "expected"), + [ + ("litellm", "litellm_spend_update_buffer", "litellm:litellm_spend_update_buffer"), + ("litellm", "litellm_config:param:general_settings", "litellm:litellm_config:param:general_settings"), + ("litellm", "litellm:3997c4abcdef", "litellm:3997c4abcdef"), + ("litellm", "spend:key:3997c4abcdef", "litellm:spend:key:3997c4abcdef"), + (None, "litellm_spend_update_buffer", "litellm_spend_update_buffer"), + ], +) +def test_check_and_fix_namespace_prefixes_keys_sharing_the_namespace_prefix( + namespace, key, expected, monkeypatch, redis_no_ping +): + """A key whose name merely begins with the namespace string (e.g. + litellm_spend_update_buffer under namespace "litellm") is not namespaced + yet and must still get the "namespace:" prefix; only a key already carrying + the delimited prefix is left alone. Without this, spend update buffers and + litellm_config:param:* keys reach Redis unprefixed and NOPERM under an ACL + scoped to the namespace pattern.""" + monkeypatch.setenv("REDIS_HOST", "https://my-test-host") + redis_cache = RedisCache(namespace=namespace) + assert redis_cache.check_and_fix_namespace(key=key) == expected + + @pytest.mark.parametrize("namespace", [None, "litellm"]) @pytest.mark.asyncio async def test_async_delete_cache_applies_namespace( From 57f553aec8348b529cb7a4254d1314e9001e0829 Mon Sep 17 00:00:00 2001 From: mateo-berri <277851410+mateo-berri@users.noreply.github.com> Date: Wed, 26 Aug 2026 13:48:45 -0700 Subject: [PATCH 2/2] fix(caching): treat an empty cache namespace as no namespace --- litellm/caching/redis_cache.py | 2 +- tests/test_litellm/caching/test_redis_cache.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/litellm/caching/redis_cache.py b/litellm/caching/redis_cache.py index d12f2066cf1..f1c80eaacbe 100644 --- a/litellm/caching/redis_cache.py +++ b/litellm/caching/redis_cache.py @@ -435,7 +435,7 @@ class RedisCache(BaseCache): """ if key is None: return key - if self.namespace is not None and not key.startswith(self.namespace + ":"): + if self.namespace and not key.startswith(self.namespace + ":"): key = self.namespace + ":" + key return key diff --git a/tests/test_litellm/caching/test_redis_cache.py b/tests/test_litellm/caching/test_redis_cache.py index 915e5eac45d..487a64797d1 100644 --- a/tests/test_litellm/caching/test_redis_cache.py +++ b/tests/test_litellm/caching/test_redis_cache.py @@ -25,6 +25,7 @@ def redis_no_ping(): ("litellm", "litellm:3997c4abcdef", "litellm:3997c4abcdef"), ("litellm", "spend:key:3997c4abcdef", "litellm:spend:key:3997c4abcdef"), (None, "litellm_spend_update_buffer", "litellm_spend_update_buffer"), + ("", "litellm_spend_update_buffer", "litellm_spend_update_buffer"), ], ) def test_check_and_fix_namespace_prefixes_keys_sharing_the_namespace_prefix(