redisson/redisson · error · IllegalStateException

Unable to find master node: ${master}

Error message

Unable to find master node: ${master}

What it means

RedissonClusterConnection.getSlaveConnection/getMasterConnection-style node resolution (method at RedissonClusterConnection.java:85, redisson-spring-data-20) throws IllegalStateException('Unable to find master node: <node>') when the node requested by the caller is not present in the topology returned by clusterGetNodes(). The lookup matches host AND port, so any host/port/id mismatch (e.g. after failover or resharding, or when nodes report internal IPs) makes masterNode null.

Source

Thrown at redisson-spring/redisson-spring-data/redisson-spring-data-20/src/main/java/org/redisson/spring/data/connection/RedissonClusterConnection.java:85

                new ObjectDecoder(new RedisClusterNodeDecoder(executorService.getServiceManager())));
        return read(null, StringCodec.INSTANCE, cluster);
    }

    @Override
    public Collection<RedisClusterNode> clusterGetSlaves(RedisClusterNode master) {
        Iterable<RedisClusterNode> res = clusterGetNodes();
        RedisClusterNode masterNode = null;
        for (Iterator<RedisClusterNode> iterator = res.iterator(); iterator.hasNext();) {
            RedisClusterNode redisClusterNode = iterator.next();
            if (master.getHost().equals(redisClusterNode.getHost()) 
                    && master.getPort().equals(redisClusterNode.getPort())) {
                masterNode = redisClusterNode;
                break;
            }
        }
        
        if (masterNode == null) {
            throw new IllegalStateException("Unable to find master node: " + master);
        }
        
        for (Iterator<RedisClusterNode> iterator = res.iterator(); iterator.hasNext();) {
            RedisClusterNode redisClusterNode = iterator.next();
            if (redisClusterNode.getMasterId() == null 
                    || !redisClusterNode.getMasterId().equals(masterNode.getId())) {
                iterator.remove();
            }
        }
        return (Collection<RedisClusterNode>) res;
    }

    @Override
    public Map<RedisClusterNode, Collection<RedisClusterNode>> clusterGetMasterSlaveMap() {
        Iterable<RedisClusterNode> res = clusterGetNodes();
        
        Set<RedisClusterNode> masters = new HashSet<RedisClusterNode>();
        for (Iterator<RedisClusterNode> iterator = res.iterator(); iterator.hasNext();) {

View on GitHub (pinned to 91188987c2)

Solutions

  1. Always obtain RedisClusterNode instances from clusterGetNodes()/clusterGetSlots() at call time instead of caching or constructing them manually
  2. Refresh the node view (clusterGetNodes) and retry once when this exception occurs
  3. For NAT/Docker deployments configure cluster-announce-ip / cluster-announce-port so advertised host:port match what the client sees
  4. Match by node Id when possible rather than host:port, since Ids are stable across DNS changes

Example fix

// before
RedisClusterNode stale = cachedNode; // captured minutes ago
connection.getClientList(stale); // may throw after failover

// after
RedisClusterNode master = connection.clusterGetNodes().stream()
    .filter(n -> n.getId().equals(wantedId))
    .findFirst().orElseThrow();
connection.getClientList(master);
Defensive patterns

Strategy: fallback

Validate before calling

// Resolve nodes fresh and match by stable Id before node-specific calls
Collection<RedisClusterNode> nodes = clusterConnection.clusterGetNodes();
Optional<RedisClusterNode> target = nodes.stream()
    .filter(n -> n.getId().equals(wantedId))
    .findFirst();
if (!target.isPresent()) {
    nodes = clusterConnection.clusterGetNodes(); // refresh topology once
    target = nodes.stream().filter(n -> n.getId().equals(wantedId)).findFirst();
}
// proceed only if target.isPresent()

Type guard

Optional<RedisClusterNode> resolveNode(RedisClusterConnection c, String nodeId) {
    return c.clusterGetNodes().stream()
        .filter(n -> n.getId().equals(nodeId)).findFirst();
}

Try / catch

catch (IllegalStateException e) {
    if (e.getMessage() != null && e.getMessage().contains("Unable to find master node")) {
        // refresh clusterGetNodes() and retry once; else surface topology-change alert
    } else throw e;
}

Prevention

When it happens

Trigger: Passing a RedisClusterNode to a node-specific operation (e.g. getClientList(node), node-specific reads/writes) whose host:port does not exactly equal any node in CLUSTER NODES output — typically because the caller cached a stale node view, the cluster failed over, or NAT/Docker maps advertised ports differently.

Common situations: Redis Cluster in Docker/K8s with NAT where nodes advertise internal IPs (announcedIP missing); a cached RedisClusterNode from a previous topology used after failover; comparing a node built from config (e.g. 127.0.0.1:7000) with the topology entry (10.0.0.5:7000); slot migration in progress.

Related errors


AI-assisted analysis of redisson/redisson@91188987c2 (2026-08-14). Data as JSON: /api/errors/66df4d6e8ab3a959. Report an issue: GitHub.