redis/redis-py · error · ValueError

Eviction policy should be associated with valid cache.

Error message

Eviction policy should be associated with valid cache.

What it means

Raised as ValueError in LRUPolicy._assert_cache (called by evict_next, evict_many, touch) when self.cache is None or is not an instance of CacheInterface. The eviction policy must be bound to a concrete cache before it can operate; without one, popitem/touch have no collection to act on.

Solutions

  1. Assign the policy to a cache before use: policy.cache = cache_instance (normally CacheConfig does this).
  2. Construct the cache via CacheConfig so the eviction policy is bound automatically.
  3. Ensure nothing resets eviction_policy.cache to None after setup.

Example fix

# before
policy = LRUPolicy()
policy.evict_next()  # ValueError: no cache
# after
policy = LRUPolicy()
policy.cache = DefaultCache(CacheConfig())
policy.evict_next()
Defensive patterns

Strategy: validation

Validate before calling

if not isinstance(policy.cache, CacheInterface):
    policy.cache = DefaultCache(CacheConfig())
policy.evict_next()

Type guard

from redis.cache import CacheInterface
def policy_has_cache(policy) -> bool:
    return isinstance(getattr(policy, "cache", None), CacheInterface)

Try / catch

try:
    policy.evict_next()
except ValueError as e:
    if "valid cache" in str(e):
        policy.cache = DefaultCache(CacheConfig())
    else:
        raise

Prevention

When it happens

Trigger: Constructing an LRUPolicy and calling evict_next/evict_many/touch before the policy has been assigned to a cache (policy.cache = cache). Also if cache was explicitly set to None. This is typically an internal misconfiguration in CSC setup.

Common situations: Using an eviction policy standalone without wiring it to a Cache. A bug in CacheConfig assembly that leaves the policy unbound. Resetting cache to None while the policy still references it.

Related errors


AI-assisted analysis of redis/redis-py@6a6b581b48 (2026-08-10). Data as JSON: /api/errors/2440382aae3f1ad2. Report an issue: GitHub.

Appendix: source

Thrown at redis/cache.py:349

        popped_keys = []

        for _ in range(count):
            popped_entry = self._cache.collection.popitem(last=False)
            popped_keys.append(popped_entry[0])

        return popped_keys

    def touch(self, cache_key: CacheKey) -> None:
        self._assert_cache()

        if self._cache.collection.get(cache_key) is None:
            raise ValueError("Given entry does not belong to the cache")

        self._cache.collection.move_to_end(cache_key)

    def _assert_cache(self):
        if self.cache is None or not isinstance(self.cache, CacheInterface):
            raise ValueError("Eviction policy should be associated with valid cache.")


class EvictionPolicy(Enum):
    LRU = LRUPolicy


class CacheConfig(CacheConfigurationInterface):
    DEFAULT_CACHE_CLASS = DefaultCache
    DEFAULT_EVICTION_POLICY = EvictionPolicy.LRU
    DEFAULT_MAX_SIZE = 10000

    DEFAULT_ALLOW_LIST = [
        "BITCOUNT",
        "BITFIELD_RO",
        "BITPOS",
        "EXISTS",
        "GEODIST",
        "GEOHASH",

View on GitHub (pinned to 6a6b581b48)