{"record":{"id":"1da24723581937d0","repo":"redisson/redisson","slug":"unable-to-find-master-node","errorCode":null,"errorMessage":"Unable to find master node: ","messagePattern":"Unable to find master node: ","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"redisson-spring/redisson-spring-data/redisson-spring-data-17/src/main/java/org/redisson/spring/data/connection/RedissonClusterConnection.java","lineNumber":81,"sourceCode":"                new ObjectDecoder(new RedisClusterNodeDecoder(executorService.getServiceManager())));\n        return read(null, StringCodec.INSTANCE, cluster);\n    }\n\n    @Override\n    public Collection<RedisClusterNode> clusterGetSlaves(RedisClusterNode master) {\n        Iterable<RedisClusterNode> res = clusterGetNodes();\n        RedisClusterNode masterNode = null;\n        for (Iterator<RedisClusterNode> iterator = res.iterator(); iterator.hasNext();) {\n            RedisClusterNode redisClusterNode = iterator.next();\n            if (master.getHost().equals(redisClusterNode.getHost()) \n                    && master.getPort().equals(redisClusterNode.getPort())) {\n                masterNode = redisClusterNode;\n                break;\n            }\n        }\n        \n        if (masterNode == null) {\n            throw new IllegalStateException(\"Unable to find master node: \" + master);\n        }\n        \n        for (Iterator<RedisClusterNode> iterator = res.iterator(); iterator.hasNext();) {\n            RedisClusterNode redisClusterNode = iterator.next();\n            if (redisClusterNode.getMasterId() == null \n                    || !redisClusterNode.getMasterId().equals(masterNode.getId())) {\n                iterator.remove();\n            }\n        }\n        return (Collection<RedisClusterNode>) res;\n    }\n\n    @Override\n    public Map<RedisClusterNode, Collection<RedisClusterNode>> clusterGetMasterSlaveMap() {\n        Iterable<RedisClusterNode> res = clusterGetNodes();\n        \n        Set<RedisClusterNode> masters = new HashSet<RedisClusterNode>();\n        for (Iterator<RedisClusterNode> iterator = res.iterator(); iterator.hasNext();) {","sourceCodeStart":63,"sourceCodeEnd":99,"githubUrl":"https://github.com/redisson/redisson/blob/91188987c2a9023e7fedabff758681ad9b107f25/redisson-spring/redisson-spring-data/redisson-spring-data-17/src/main/java/org/redisson/spring/data/connection/RedissonClusterConnection.java#L63-L99","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nRedisClusterNode master = new RedisClusterNode(\"redis.example.com\", 6379); // hostname\nconnection.clusterGetReplicas(master); // cluster advertises 10.0.0.5:6379 -> throws\n\n// after\nIterable<RedisClusterNode> nodes = connection.clusterGetNodes();\nRedisClusterNode master = StreamSupport.stream(nodes.spliterator(), false)\n        .filter(RedisClusterNode::isMaster)\n        .filter(n -> n.getHost().equals(\"10.0.0.5\"))\n        .findFirst().orElseThrow();\nconnection.clusterGetReplicas(master);","handlingStrategy":"validation","validationCode":"// always source nodes from the cluster itself\nRedisClusterNode match = StreamSupport.stream(connection.clusterGetNodes().spliterator(), false)\n        .filter(n -> n.getHost().equals(master.getHost()) && n.getPort() == master.getPort())\n        .findFirst().orElseThrow(() ->\n            new IllegalStateException(\"master \" + master + \" not in current topology; refresh clusterGetNodes\"));\nconnection.clusterGetReplicas(match);","typeGuard":"boolean nodeInTopology(RedisClusterNode node, Iterable<RedisClusterNode> topology) {\n    return StreamSupport.stream(topology.spliterator(), false)\n        .anyMatch(n -> n.getHost().equals(node.getHost())\n                    && n.getPort() == node.getPort());\n}","tryCatchPattern":"try {\n    return connection.clusterGetReplicas(master);\n} catch (IllegalStateException e) {\n    if (e.getMessage().startsWith(\"Unable to find master node\")) {\n        Iterable<RedisClusterNode> fresh = connection.clusterGetNodes();\n        // retry with a node taken from the refreshed topology\n    }\n    throw e;\n}","preventionTips":["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"],"tags":["spring-data-redis","cluster","topology","docker","nat"],"backgroundTag":null,"analyzedSha":"91188987c2a9023e7fedabff758681ad9b107f25","analyzedAt":"2026-08-14T11:39:42.619Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}