dromara/Sa-Token · critical · SaTokenException

Alone-Redis 集群模式需要配置 cluster.nodes

Error message

Alone-Redis 集群模式需要配置 cluster.nodes

What it means

SaTokenException thrown by SaAloneRedisInject (spring-boot4 variant of sa-token-alone-redis) when sa-token.alone-redis.pattern=cluster is configured but the nested cluster.nodes list is absent. The injector builds a RedisClusterConfiguration and cannot proceed without at least one 'host:port' node entry.

Source

Thrown at sa-token-plugin/sa-token-alone-redis-by-spring-boot4/src/main/java/cn/dev33/satoken/dao/alone/SaAloneRedisInject.java:107

			if (pattern.equals("single")) {
				// 单体模式
				RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
				redisConfig.setHostName(cfg.getHost());
				redisConfig.setPort(cfg.getPort());
				redisConfig.setDatabase(cfg.getDatabase());
				redisConfig.setPassword(RedisPassword.of(cfg.getPassword()));
				redisConfig.setUsername(cfg.getUsername());
				redisAloneConfig = redisConfig;

			} else if (pattern.equals("cluster")){
				// 普通集群模式
				RedisClusterConfiguration redisClusterConfig = new RedisClusterConfiguration();
				redisClusterConfig.setUsername(cfg.getUsername());
				redisClusterConfig.setPassword(RedisPassword.of(cfg.getPassword()));

				DataRedisProperties.Cluster cluster = cfg.getCluster();
				if (cluster == null || cluster.getNodes() == null) {
					throw new SaTokenException("Alone-Redis 集群模式需要配置 cluster.nodes");
				}
				List<RedisNode> serverList = cluster.getNodes().stream().map(node -> {
					String[] ipAndPort = node.split(":");
					return new RedisNode(ipAndPort[0].trim(), Integer.parseInt(ipAndPort[1]));
				}).collect(Collectors.toList());
				redisClusterConfig.setClusterNodes(serverList);
				if (cluster.getMaxRedirects() != null) {
					redisClusterConfig.setMaxRedirects(cluster.getMaxRedirects());
				}
				redisAloneConfig = redisClusterConfig;
			} else if (pattern.equals("sentinel")) {
				// 哨兵集群模式
				RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration();
				redisSentinelConfiguration.setDatabase(cfg.getDatabase());
				redisSentinelConfiguration.setUsername(cfg.getUsername());
				redisSentinelConfiguration.setPassword(RedisPassword.of(cfg.getPassword()));

				DataRedisProperties.Sentinel sentinel = cfg.getSentinel();

View on GitHub (pinned to ac2c7f6e94)

Solutions

  1. Add the nodes list, e.g. sa-token.alone-redis.cluster.nodes: ["10.0.0.1:6379", "10.0.0.2:6379"].
  2. Check yaml indentation so cluster: sits under sa-token.alone-redis, and nodes: is a list of host:port strings.
  3. Optionally set cluster.max-redirects (e.g. 3) as recommended for Redis Cluster.
  4. Verify pattern value is exactly 'cluster' (not 'redis-cluster') so this branch is the one requiring the config.

Example fix

# before
sa-token:
  alone-redis:
    pattern: cluster

# after
sa-token:
  alone-redis:
    pattern: cluster
    cluster:
      max-redirects: 3
      nodes:
        - 10.0.0.1:6379
        - 10.0.0.2:6379
        - 10.0.0.3:6379
Defensive patterns

Strategy: validation

Validate before calling

// at startup / config check, before the injector runs
if ("cluster".equals(props.getPattern()) && (props.getCluster() == null || props.getCluster().getNodes() == null || props.getCluster().getNodes().isEmpty())) {
    throw new IllegalStateException("alone-redis cluster mode requires cluster.nodes");
}

Prevention

When it happens

Trigger: Setting sa-token.alone-redis.pattern=cluster in application.yml without a sa-token.alone-redis.cluster.nodes: [host:port, ...] block (or misspelling 'nodes' / nesting it under the wrong level so Spring Boot's DataRedisProperties.Cluster stays null).

Common situations: Migrating a standalone alone-redis config to a cluster by only changing pattern; yaml indentation errors putting cluster.nodes under sa-token instead of sa-token.alone-redis.cluster.nodes; copying config from the non-boot4 plugin whose property paths differ.

Related errors


AI-assisted analysis of dromara/Sa-Token@ac2c7f6e94 (2026-08-14). Data as JSON: /api/errors/b23c1786b17d27c6. Report an issue: GitHub.