{"record":{"id":"c98c0a3c591f78e9","repo":"alibaba/spring-cloud-alibaba","slug":"serveraddr-groupid-and-dataid-must-not-be-null","errorCode":null,"errorMessage":"serverAddr, groupId, and dataId must not be null","messagePattern":"serverAddr, groupId, and dataId must not be null","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/ZookeeperDataSourceFactoryBean.java","lineNumber":49,"sourceCode":" */\npublic class ZookeeperDataSourceFactoryBean implements FactoryBean<ZookeeperDataSource> {\n\n\tprivate @Nullable String serverAddr;\n\n\tprivate @Nullable String path;\n\n\tprivate @Nullable String groupId;\n\n\tprivate @Nullable String dataId;\n\n\tprivate @Nullable Converter converter;\n\n\t@Override\n\tpublic ZookeeperDataSource getObject() throws Exception {\n\t\tif (StringUtils.isNotEmpty(groupId) && StringUtils.isNotEmpty(dataId)) {\n\t\t\t// the path will be /{groupId}/{dataId}\n\t\t\tif (serverAddr == null || groupId == null || dataId == null) {\n\t\t\t\tthrow new IllegalStateException(\"serverAddr, groupId, and dataId must not be null\");\n\t\t\t}\n\t\t\treturn new ZookeeperDataSource(serverAddr, groupId, dataId, converter);\n\t\t}\n\t\telse {\n\t\t\t// using path directly\n\t\t\tif (serverAddr == null || path == null) {\n\t\t\t\tthrow new IllegalStateException(\"serverAddr and path must not be null\");\n\t\t\t}\n\t\t\treturn new ZookeeperDataSource(serverAddr, path, converter);\n\t\t}\n\t}\n\n\t@Override\n\tpublic Class<?> getObjectType() {\n\t\treturn ZookeeperDataSource.class;\n\t}\n\n\tpublic @Nullable String getServerAddr() {","sourceCodeStart":31,"sourceCodeEnd":67,"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/ZookeeperDataSourceFactoryBean.java#L31-L67","documentation":"Thrown by ZookeeperDataSourceFactoryBean.getObject() in the groupId/dataId branch when serverAddr is null. IMPORTANT: the outer condition checks isNotEmpty(groupId) && isNotEmpty(dataId), which guarantees both are non-null and non-blank. Therefore the inner check 'groupId == null || dataId == null' is dead code — this error can ONLY fire when serverAddr is null while groupId and dataId are both provided. The message lists all three for documentation purposes but the practical trigger is a missing serverAddr.","triggerScenarios":"Configuring a Sentinel datasource of type 'zk' with groupId and dataId both set (non-empty) but serverAddr not provided (null). The FactoryBean enters the groupId/dataId branch, and the serverAddr null check at line 48 triggers.","commonSituations":"1) Developer provides zk.group-id and zk.data-id but forgets zk.server-addr. 2) serverAddr placeholder (${ZK_ADDR}) is not set in the environment and resolves to null (note: ZookeeperDataSourceProperties defaults serverAddr to 'localhost:2181', but if the FactoryBean is wired directly or the property is explicitly cleared, it can be null). 3) Programmatic FactoryBean creation with groupId/dataId set but serverAddr omitted.","solutions":["Set spring.cloud.sentinel.datasource.<name>.zk.server-addr=<zk-host:port> to a valid Zookeeper address.","Verify that ZookeeperDataSourceProperties.serverAddr (which defaults to 'localhost:2181') is not being overridden to null or empty by a profile or programmatic config.","If constructing the FactoryBean programmatically, call setServerAddr() before getObject()."],"exampleFix":"# before (broken — serverAddr missing)\nspring:\n  cloud:\n    sentinel:\n      datasource:\n        ds1:\n          zk:\n            group-id: sentinel\n            data-id: flow-rules\n\n# after (fixed)\nspring:\n  cloud:\n    sentinel:\n      datasource:\n        ds1:\n          zk:\n            server-addr: zk.local:2181\n            group-id: sentinel\n            data-id: flow-rules","handlingStrategy":"validation","validationCode":"// Validate ZookeeperDataSourceFactoryBean properties before getObject()\nZookeeperDataSourceFactoryBean fb = new ZookeeperDataSourceFactoryBean();\nif (StringUtils.isNotEmpty(groupId) && StringUtils.isNotEmpty(dataId)) {\n    if (serverAddr == null) {\n        throw new IllegalStateException(\"serverAddr is required when using groupId/dataId mode\");\n    }\n} else {\n    if (serverAddr == null || path == null) {\n        throw new IllegalStateException(\"serverAddr and path are required in path mode\");\n    }\n}\nfb.setServerAddr(serverAddr);\nfb.setGroupId(groupId);\nfb.setDataId(dataId);\nfb.setConverter(converter);\nfb.getObject();","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always set server-addr when configuring a ZK Sentinel datasource — the properties default is 'localhost:2181' but explicit is safer.","When using groupId/dataId mode, ensure BOTH are non-empty — an empty dataId silently switches to path mode.","Verify ZK connectivity and node paths before deployment."],"tags":["sentinel","zookeeper","datasource","factory-bean","configuration","validation"],"backgroundTag":null,"analyzedSha":"115d5901102009492e05d5ec18c3f79cad4077d0","analyzedAt":"2026-08-14T04:47:13.900Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}