{"record":{"id":"d8bb69b53995c316","repo":"dromara/Sa-Token","slug":"alone-redis-sentinel-nodes","errorCode":null,"errorMessage":"Alone-Redis 哨兵模式需要配置 sentinel.nodes","messagePattern":"Alone-Redis 哨兵模式需要配置 sentinel\\.nodes","errorType":"validation","errorClass":"SaTokenException","httpStatus":null,"severity":"critical","filePath":"sa-token-plugin/sa-token-alone-redis-by-spring-boot4/src/main/java/cn/dev33/satoken/dao/alone/SaAloneRedisInject.java","lineNumber":127,"sourceCode":"\t\t\t\tList<RedisNode> serverList = cluster.getNodes().stream().map(node -> {\n\t\t\t\t\tString[] ipAndPort = node.split(\":\");\n\t\t\t\t\treturn new RedisNode(ipAndPort[0].trim(), Integer.parseInt(ipAndPort[1]));\n\t\t\t\t}).collect(Collectors.toList());\n\t\t\t\tredisClusterConfig.setClusterNodes(serverList);\n\t\t\t\tif (cluster.getMaxRedirects() != null) {\n\t\t\t\t\tredisClusterConfig.setMaxRedirects(cluster.getMaxRedirects());\n\t\t\t\t}\n\t\t\t\tredisAloneConfig = redisClusterConfig;\n\t\t\t} else if (pattern.equals(\"sentinel\")) {\n\t\t\t\t// 哨兵集群模式\n\t\t\t\tRedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();\n\t\t\t\tredisSentinelConfiguration.setDatabase(cfg.getDatabase());\n\t\t\t\tredisSentinelConfiguration.setUsername(cfg.getUsername());\n\t\t\t\tredisSentinelConfiguration.setPassword(RedisPassword.of(cfg.getPassword()));\n\n\t\t\t\tDataRedisProperties.Sentinel sentinel = cfg.getSentinel();\n\t\t\t\tif (sentinel == null || sentinel.getNodes() == null) {\n\t\t\t\t\tthrow new SaTokenException(\"Alone-Redis 哨兵模式需要配置 sentinel.nodes\");\n\t\t\t\t}\n\t\t\t\tredisSentinelConfiguration.setMaster(sentinel.getMaster());\n\t\t\t\tredisSentinelConfiguration.setSentinelPassword(sentinel.getPassword());\n\t\t\t\tList<RedisNode> serverList = sentinel.getNodes().stream().map(node -> {\n\t\t\t\t\tString[] ipAndPort = node.split(\":\");\n\t\t\t\t\treturn new RedisNode(ipAndPort[0].trim(), Integer.parseInt(ipAndPort[1]));\n\t\t\t\t}).collect(Collectors.toList());\n\t\t\t\tredisSentinelConfiguration.setSentinels(serverList);\n\n\t\t\t\tredisAloneConfig = redisSentinelConfiguration;\n\t\t\t} else if (pattern.equals(\"socket\")) {\n\t\t\t\t// socket 连接单体 Redis\n\t\t\t\tRedisSocketConfiguration redisSocketConfiguration = new RedisSocketConfiguration();\n\t\t\t\tredisSocketConfiguration.setDatabase(cfg.getDatabase());\n\t\t\t\tredisSocketConfiguration.setUsername(cfg.getUsername());\n\t\t\t\tredisSocketConfiguration.setPassword(RedisPassword.of(cfg.getPassword()));\n\t\t\t\tString socket = environment.getProperty(ALONE_PREFIX + \".socket\", \"\");\n\t\t\t\tredisSocketConfiguration.setSocket(socket);","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/dromara/Sa-Token/blob/ac2c7f6e94a78573cf0bcb932dd8b04e68fad189/sa-token-plugin/sa-token-alone-redis-by-spring-boot4/src/main/java/cn/dev33/satoken/dao/alone/SaAloneRedisInject.java#L109-L145","documentation":"SaTokenException thrown by SaAloneRedisInject (spring-boot4 variant) when sa-token.alone-redis.pattern=sentinel is configured but sentinel.nodes is missing. Building a RedisSentinelConfiguration requires the sentinel node addresses; the master name and sentinel password are read afterwards but the node list is the hard prerequisite.","triggerScenarios":"Setting sa-token.alone-redis.pattern=sentinel without a sa-token.alone-redis.sentinel.nodes list, or with nodes nested incorrectly so DataRedisProperties.Sentinel#getNodes() returns null. The check also fires when the whole sentinel: block is omitted (sentinel == null).","commonSituations":"Switching the alone-redis connection to a sentinel deployment and forgetting the topology block; yaml indentation mistakes; providing only sentinel.master and assuming nodes are inferred.","solutions":["Add sa-token.alone-redis.sentinel.nodes: [\"sentinel1:26379\", \"sentinel2:26379\"] and sentinel.master: mymaster.","Fix yaml nesting so sentinel: is a child of sa-token.alone-redis.","Set sentinel.password if the sentinels themselves require auth.","Confirm pattern is exactly 'sentinel'."],"exampleFix":"# before\nsa-token:\n  alone-redis:\n    pattern: sentinel\n    sentinel:\n      master: mymaster\n\n# after\nsa-token:\n  alone-redis:\n    pattern: sentinel\n    sentinel:\n      master: mymaster\n      password: sentinel-pass\n      nodes:\n        - 10.0.0.1:26379\n        - 10.0.0.2:26379\n        - 10.0.0.3:26379","handlingStrategy":"validation","validationCode":"if (\"sentinel\".equals(props.getPattern()) && (props.getSentinel() == null || props.getSentinel().getNodes() == null)) {\n    throw new IllegalStateException(\"alone-redis sentinel mode requires sentinel.nodes and master\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["For sentinel always configure nodes AND master together; nodes without master fails later at Redisson/Lettuce level.","Use a yaml schema check (IDE plugin or spring-boot-configuration-metadata) to catch missing nested keys early."],"tags":["alone-redis","redis-sentinel","spring-boot4","configuration"],"backgroundTag":null,"analyzedSha":"ac2c7f6e94a78573cf0bcb932dd8b04e68fad189","analyzedAt":"2026-08-14T14:36:10.271Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}