redis/redis-py · error · RedisClusterException

RedisCluster requires at least one node to discover the…

Error message

RedisCluster requires at least one node to discover the cluster.
Please provide one of the following or use RedisCluster.from_url:
   - host and port: RedisCluster(host="localhost", port=6379)
   - startup_nodes: RedisCluster(startup_nodes=[ClusterNode("localhost", 6379), ClusterNode("localhost", 6380)])

What it means

Raised in RedisCluster.__init__ when neither (host and port) nor startup_nodes is provided. The cluster client needs at least one seed node to bootstrap slot/topology discovery via CLUSTER NODES / CLUSTER SHARDS. With no seed it cannot discover anything, so construction fails fast with a hint pointing at from_url as an alternative.

Solutions

  1. Provide host and port: RedisCluster(host='localhost', port=7000).
  2. Or provide startup_nodes=[ClusterNode('host', port), ...].
  3. Or use RedisCluster.from_url('redis://host:port') which parses the URL into a seed node.

Example fix

// before
client = RedisCluster()
// after
client = RedisCluster(host='localhost', port=7000)
# or
client = RedisCluster.from_url('redis://localhost:7000')
Defensive patterns

Strategy: validation

Validate before calling

has_seed = (host and port) or bool(startup_nodes)
assert has_seed, 'RedisCluster needs host+port or startup_nodes'
client = RedisCluster(host=host, port=port, startup_nodes=startup_nodes)

Type guard

def has_cluster_seed(host, port, startup_nodes) -> bool:
    return bool((host and port) or startup_nodes)

Try / catch

from redis.exceptions import RedisClusterException
try:
    client = RedisCluster(host=host, port=port)
except RedisClusterException as e:
    if 'at least one node' in str(e):
        client = RedisCluster.from_url(os.environ['REDIS_URL'])
    else:
        raise

Prevention

When it happens

Trigger: RedisCluster() with no args; RedisCluster(host='localhost') missing port; passing only host or only port; passing an empty startup_nodes list.

Common situations: Building a cluster client from environment variables where REDIS_HOST/REDIS_PORT are unset in one environment; misconfiguring service discovery; copy-paste dropping the port argument.

Related errors


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

Appendix: source

Thrown at redis/asyncio/cluster.py:472

        protocol: int | None = None,
        legacy_responses: bool = True,
        address_remap: Callable[[Tuple[str, int]], Tuple[str, int]] | None = None,
        event_dispatcher: EventDispatcher | None = None,
        policy_resolver: AsyncPolicyResolver = AsyncStaticPolicyResolver(),
        maint_notifications_config: MaintNotificationsConfig | None = None,
    ) -> None:
        if db:
            raise RedisClusterException(
                "Argument 'db' must be 0 or None in cluster mode"
            )

        if path:
            raise RedisClusterException(
                "Unix domain socket is not supported in cluster mode"
            )

        if (not host or not port) and not startup_nodes:
            raise RedisClusterException(
                "RedisCluster requires at least one node to discover the cluster.\n"
                "Please provide one of the following or use RedisCluster.from_url:\n"
                '   - host and port: RedisCluster(host="localhost", port=6379)\n'
                "   - startup_nodes: RedisCluster(startup_nodes=["
                'ClusterNode("localhost", 6379), ClusterNode("localhost", 6380)])'
            )

        computed_driver_info = resolve_driver_info(driver_info, lib_name, lib_version)

        kwargs: Dict[str, Any] = {
            "max_connections": max_connections,
            "connection_class": Connection,
            # Client related kwargs
            "credential_provider": credential_provider,
            "username": username,
            "password": password,
            "client_name": client_name,
            "driver_info": computed_driver_info,

View on GitHub (pinned to 6a6b581b48)