{"record":{"id":"2e10edc14eb0e692","repo":"alibaba/spring-cloud-alibaba","slug":"invalid-redis-sentinel-property","errorCode":null,"errorMessage":"Invalid redis sentinel property {}","messagePattern":"Invalid redis sentinel property (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"spring-cloud-alibaba-starters/spring-cloud-alibaba-sentinel-datasource/src/main/java/com/alibaba/cloud/sentinel/datasource/factorybean/RedisDataSourceFactoryBean.java","lineNumber":87,"sourceCode":"\n\tprivate @Nullable String masterId;\n\n\t@Override\n\tpublic RedisDataSource getObject() {\n\t\tRedisConnectionConfig.Builder builder = RedisConnectionConfig.builder();\n\n\t\tif (nodes == null || nodes.isEmpty()) {\n\t\t\tbuilder.withHost(host).withPort(port).withDatabase(database);\n\t\t}\n\t\telse {\n\t\t\tnodes.forEach(node -> {\n\t\t\t\ttry {\n\t\t\t\t\tString[] parts = StringUtils.split(node, \":\");\n\t\t\t\t\tAssert.state(parts != null && parts.length == 2, \"Must be defined as 'host:port'\");\n\t\t\t\t\tbuilder.withRedisSentinel(parts[0], Integer.parseInt(parts[1]));\n\t\t\t\t}\n\t\t\t\tcatch (RuntimeException ex) {\n\t\t\t\t\tthrow new IllegalStateException(\n\t\t\t\t\t\t\t\"Invalid redis sentinel property \" + node, ex);\n\t\t\t\t}\n\t\t\t});\n\t\t\tbuilder.withSentinelMasterId(masterId);\n\t\t}\n\n\t\tif (timeout != null) {\n\t\t\tbuilder.withTimeout(timeout.toMillis());\n\t\t}\n\n\t\tif (StringUtils.hasText(password)) {\n\t\t\tbuilder.withPassword(password);\n\t\t}\n\n\t\treturn new RedisDataSource<List<FlowRule>>(builder.build(), ruleKey, channel,\n\t\t\t\tconverter);\n\t}\n","sourceCodeStart":69,"sourceCodeEnd":105,"githubUrl":"https://github.com/alibaba/spring-cloud-alibaba/blob/115d5901102009492e05d5ec18c3f79cad4077d0/spring-cloud-alibaba-starters/spring-cloud-alibaba-sentinel-datasource/src/main/java/com/alibaba/cloud/sentinel/datasource/factorybean/RedisDataSourceFactoryBean.java#L69-L105","documentation":"Thrown by RedisDataSourceFactoryBean.getObject() when parsing a Redis Sentinel node entry fails. The FactoryBean iterates over the nodes list (each expected as 'host:port'), splits on ':', and asserts exactly two parts. If split returns null, yields != 2 parts, or Integer.parseInt(parts[1]) fails, the RuntimeException is caught and wrapped in an IllegalStateException identifying the offending node value.","triggerScenarios":"Configuring spring.cloud.sentinel.datasource.<name>.redis.nodes with one or more entries that do not match the 'host:port' format. Examples: missing port ('redis.local'), extra colons ('redis.local:6379:extra'), non-numeric port ('redis.local:abc'), or whitespace-only entries after splitting.","commonSituations":"1) Node list entries use a different separator (e.g., 'redis.local 6379' with space instead of colon). 2) Port is omitted from one or more sentinel entries. 3) A trailing comma creates an empty entry in the list. 4) Non-numeric characters in the port field.","solutions":["Format every node entry as exactly 'host:port' with a numeric port: e.g., redis-sentinel-1.local:26379,redis-sentinel-2.local:26379.","Check for trailing commas, empty entries, or whitespace in the nodes list.","Ensure the port is numeric and within valid range (1-65535)."],"exampleFix":"# before (broken — missing port, trailing comma)\nspring:\n  cloud:\n    sentinel:\n      datasource:\n        ds1:\n          redis:\n            nodes:\n              - redis-sentinel-1.local\n              - redis-sentinel-2.local:26379,\n\n# after (fixed)\nspring:\n  cloud:\n    sentinel:\n      datasource:\n        ds1:\n          redis:\n            nodes:\n              - redis-sentinel-1.local:26379\n              - redis-sentinel-2.local:26379","handlingStrategy":"validation","validationCode":"import java.util.List;\nimport org.springframework.util.StringUtils;\n\n// Validate each node entry before FactoryBean.getObject()\nList<String> nodes = props.getRedis().getNodes();\nif (nodes != null) {\n    for (String node : nodes) {\n        String[] parts = StringUtils.split(node, \":\");\n        if (parts == null || parts.length != 2) {\n            throw new IllegalArgumentException(\n                \"Invalid redis sentinel node format: '\" + node + \"' — must be 'host:port'\");\n        }\n        try {\n            int port = Integer.parseInt(parts[1]);\n            if (port < 1 || port > 65535) {\n                throw new IllegalArgumentException(\"Port out of range: \" + port);\n            }\n        } catch (NumberFormatException e) {\n            throw new IllegalArgumentException(\n                \"Invalid port number in node: '\" + node + \"'\");\n        }\n    }\n}","typeGuard":"import java.util.regex.Pattern;\n\nprivate static final Pattern HOST_PORT = Pattern.compile(\"^[^:]+:[0-9]{1,5}$\");\n\nboolean isValidNode(String node) {\n    return node != null && HOST_PORT.matcher(node.trim()).matches();\n}","tryCatchPattern":null,"preventionTips":["Always format Redis Sentinel nodes as 'host:port' with numeric ports.","Avoid trailing commas or empty entries in the nodes list.","Validate node entries in a configuration test or startup health check.","Use consistent YAML list formatting to avoid parsing ambiguities."],"tags":["sentinel","redis","datasource","sentinel-mode","factory-bean","configuration","validation"],"backgroundTag":null,"analyzedSha":"115d5901102009492e05d5ec18c3f79cad4077d0","analyzedAt":"2026-08-14T04:47:13.900Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}