redisson/redisson · error · IllegalStateException
Unable to find master node:
Error message
Unable to find master node:
What it means
RedissonClusterConnection.clusterGetReplicas (called with a master) fetches the cluster node list via CLUSTER NODES and searches it for a node whose host and port match the given master. If no advertised node matches, it throws IllegalStateException('Unable to find master node: ' + master). The comparison is exact string equality on host and port, so mismatches arise when the cluster advertises different host identifiers (IP vs hostname, NAT/Docker addresses) than the node object the caller supplied.
Source
Thrown at redisson-spring/redisson-spring-data/redisson-spring-data-17/src/main/java/org/redisson/spring/data/connection/RedissonClusterConnection.java:81
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
- Pass a RedisClusterNode obtained from clusterGetNodes() itself rather than constructing one manually — its host/port come from the cluster's own advertisement
- Fix advertised addresses on the Redis cluster (cluster-announce-ip / cluster-announce-port in redis.conf or Docker command) so the topology the app sees is connectable and consistent
- Refresh topology (re-invoke clusterGetNodes) instead of reusing node objects across failovers/reshards
Example fix
// before
RedisClusterNode master = new RedisClusterNode("redis.example.com", 6379); // hostname
connection.clusterGetReplicas(master); // cluster advertises 10.0.0.5:6379 -> throws
// after
Iterable<RedisClusterNode> nodes = connection.clusterGetNodes();
RedisClusterNode master = StreamSupport.stream(nodes.spliterator(), false)
.filter(RedisClusterNode::isMaster)
.filter(n -> n.getHost().equals("10.0.0.5"))
.findFirst().orElseThrow();
connection.clusterGetReplicas(master); Defensive patterns
Strategy: validation
Validate before calling
// always source nodes from the cluster itself
RedisClusterNode match = StreamSupport.stream(connection.clusterGetNodes().spliterator(), false)
.filter(n -> n.getHost().equals(master.getHost()) && n.getPort() == master.getPort())
.findFirst().orElseThrow(() ->
new IllegalStateException("master " + master + " not in current topology; refresh clusterGetNodes"));
connection.clusterGetReplicas(match); Type guard
boolean nodeInTopology(RedisClusterNode node, Iterable<RedisClusterNode> topology) {
return StreamSupport.stream(topology.spliterator(), false)
.anyMatch(n -> n.getHost().equals(node.getHost())
&& n.getPort() == node.getPort());
} Try / catch
try {
return connection.clusterGetReplicas(master);
} catch (IllegalStateException e) {
if (e.getMessage().startsWith("Unable to find master node")) {
Iterable<RedisClusterNode> fresh = connection.clusterGetNodes();
// retry with a node taken from the refreshed topology
}
throw e;
} Prevention
- Never hand-construct RedisClusterNode for cluster ops — use clusterGetNodes() output
- Configure cluster-announce-ip/port correctly in Docker/NAT deployments
- Re-fetch topology after failovers or resharding instead of caching node objects
When it happens
Trigger: Calling clusterGetReplicas / RedisTemplate opsForCluster().replicas(node) with a RedisClusterNode whose host/port do not literally equal any host:port in CLUSTER NODES output — typically because the caller built the node from a config hostname while the cluster advertises IPs (or vice versa), or behind NAT/container port mappings.
Common situations: Docker/Kubernetes deployments where Redis advertises internal IPs but the app resolves external hostnames; obtaining the node from a previous, stale cluster topology after a failover or reshard; passing a manually constructed RedisClusterNode instead of one returned by clusterGetNodes(); multi-NAT environments rewriting advertised ports.
Related errors
- Unable to find master node:
- Unable to find master node:
- hibernate.cache.redisson.jndi_name property not set
- Unable to find master node:
- Unable to find master node: ${master}
AI-assisted analysis of redisson/redisson@91188987c2 (2026-08-14).
Data as JSON: /api/errors/1da24723581937d0.
Report an issue: GitHub.