redis/redis-py · error · RedisError

Maintenance notifications are only supported with RESP…

Error message

Maintenance notifications are only supported with RESP version 3

What it means

Cluster-mode counterpart of error 40: RedisCluster.__init__ validates maint_notifications_config before constructing NodesManager, and raises RedisError if enabled=True but protocol != 3. Validated early so a bad config does not leak an open NodesManager.

Solutions

  1. Set protocol=3 on the RedisCluster(...) call that enables maint notifications.
  2. If RESP2 is mandatory, leave maint_notifications_config=None / enabled=False.
  3. Confirm the cluster runs Redis >= 7.x with RESP3 push support.

Example fix

// before
client = RedisCluster(
    host='localhost', port=7000,
    maint_notifications_config=MaintNotificationsConfig(enabled=True),
    protocol=2,
)
// after
client = RedisCluster(
    host='localhost', port=7000,
    maint_notifications_config=MaintNotificationsConfig(enabled=True),
    protocol=3,
)
Defensive patterns

Strategy: validation

Validate before calling

from redis._parsers.helpers import check_protocol_version
if maint_cfg and maint_cfg.enabled and not check_protocol_version(protocol, 3):
    raise ValueError('enable RESP3 (protocol=3) before cluster maint notifications')

Type guard

def can_use_cluster_maint_notifications(protocol: int | None) -> bool:
    return check_protocol_version(protocol, 3)

Try / catch

try:
    client = RedisCluster(host=..., port=..., maint_notifications_config=cfg, protocol=protocol)
except RedisError as e:
    if 'RESP version 3' in str(e):
        client = RedisCluster(host=..., port=..., maint_notifications_config=None, protocol=protocol)
    else:
        raise

Prevention

When it happens

Trigger: RedisCluster(host=..., port=..., maint_notifications_config=MaintNotificationsConfig(enabled=True), protocol=2); or enabling notifications on a cluster client while the deployment default protocol is RESP2.

Common situations: Enabling server-pushed maintenance notifications on a cluster whose other clients still negotiate RESP2; upgrading a cluster deployment and forgetting to bump protocol to 3.

Related errors


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

Appendix: source

Thrown at redis/asyncio/cluster.py:573

        # Build the client-level HIMPORT registry once (always empty at construction)
        # and share the same object with every node connection. It rides in
        # connection_kwargs -> ClusterNode -> each node's Connection, so the registry is
        # shared cluster-wide and runtime himport_prepare mutates one object. (Async has
        # no per-node Redis client, so the object flows via connection_kwargs directly to
        # the Connection, which is internal plumbing, not a public param.)
        self._himport_registry = HImportRegistry()
        kwargs["himport_registry"] = self._himport_registry

        self.connection_kwargs = kwargs

        # Validate maint_notifications_config before NodesManager is constructed
        # so that a bad config doesn't leak an open NodesManager.
        if (
            maint_notifications_config
            and maint_notifications_config.enabled
            and not check_protocol_version(protocol, 3)
        ):
            raise RedisError(
                "Maintenance notifications are only supported with RESP version 3"
            )
        if check_protocol_version(protocol, 3) and maint_notifications_config is None:
            maint_notifications_config = MaintNotificationsConfig()
        # Initialize to None so aclose() and any error-path code never sees an
        # unset slot, even if __init__ raises before the mixin runs.
        self._oss_cluster_maint_notifications_handler = None

        if startup_nodes:
            passed_nodes = []
            for node in startup_nodes:
                passed_nodes.append(
                    ClusterNode(node.host, node.port, **self.connection_kwargs)
                )
            startup_nodes = passed_nodes
        else:
            startup_nodes = []
        if host and port:

View on GitHub (pinned to 6a6b581b48)