redis/redis-py · error · ValueError

Cache must implement CacheInterface

Error message

Cache must implement CacheInterface

What it means

Raised as ValueError by ConnectionPool.__init__ when the cache argument is provided but is not an instance of CacheInterface. redis-py requires a concrete cache object that implements the CacheInterface contract (get/set/delete/flush/etc.) so the invalidation machinery can drive it. Passing a dict, a plain LRUCache from another library, or a half-implemented stub fails this check.

Solutions

  1. Pass an object that implements CacheInterface, or use cache_config to have redis-py build a default cache for you.
  2. If you have a custom cache, make the class inherit CacheInterface and implement its abstract methods.
  3. Drop the cache argument and rely on cache_config when you do not need a custom cache implementation.

Example fix

# before
pool = ConnectionPool(protocol=3, cache={'k': 'v'})
# after
pool = ConnectionPool(protocol=3, cache_config={})  # builds a CacheInterface impl
Defensive patterns

Strategy: type-guard

Validate before calling

from redis.cache import CacheInterface

def ensure_cache(cache):
    if cache is None or isinstance(cache, CacheInterface):
        return cache
    raise TypeError('cache must implement CacheInterface; pass cache_config to build a default cache')

pool = ConnectionPool(protocol=3, cache=ensure_cache(user_cache))

Type guard

from redis.cache import CacheInterface

def is_valid_cache(cache) -> bool:
    return cache is None or isinstance(cache, CacheInterface)

Try / catch

try:
    pool = ConnectionPool(protocol=3, cache=user_cache)
except ValueError as e:
    if 'Cache must implement CacheInterface' in str(e):
        pool = ConnectionPool(protocol=3, cache_config={})  # build a default cache
    else:
        raise

Prevention

When it happens

Trigger: Passing cache={'k': 'v'} or cache=cachetools.LRUCache(...) to ConnectionPool. Providing a custom cache object that does not inherit/implement CacheInterface.

Common situations: Assuming any dict-like object works as a cache. Using cache_config (which builds a default cache) vs cache (which must be a CacheInterface) interchangeably. Subclassing without implementing all abstract methods.

Related errors


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

Appendix: source

Thrown at redis/connection.py:3035

                raise RedisError(
                    "Maintenance notifications are not supported with "
                    f"{connection_class}"
                )
            maint_notifications_config = MaintNotificationsConfig(enabled=False)

        self._event_dispatcher = self._connection_kwargs.get("event_dispatcher", None)
        if self._event_dispatcher is None:
            self._event_dispatcher = EventDispatcher()

        if connection_kwargs.get("cache_config") or connection_kwargs.get("cache"):
            if not check_protocol_version(self._connection_kwargs.get("protocol"), 3):
                raise RedisError("Client caching is only supported with RESP version 3")

            cache = self._connection_kwargs.get("cache")

            if cache is not None:
                if not isinstance(cache, CacheInterface):
                    raise ValueError("Cache must implement CacheInterface")

                self.cache = cache
            else:
                if self._cache_factory is not None:
                    self.cache = CacheProxy(self._cache_factory.get_cache())
                else:
                    self.cache = CacheFactory(
                        self._connection_kwargs.get("cache_config")
                    ).get_cache()

            init_csc_items()
            register_csc_items_callback(
                callback=lambda: self.cache.size,
                pool_name=get_pool_name(self),
            )

        connection_kwargs.pop("cache", None)
        connection_kwargs.pop("cache_config", None)

View on GitHub (pinned to 6a6b581b48)