{"record":{"id":"4f2ba85a739fc558","repo":"alibaba/canal","slug":"zookeeper-create-error-serveraddrs","errorCode":null,"errorMessage":"zookeeper_create_error, serveraddrs={}","messagePattern":"zookeeper_create_error, serveraddrs=(.+?)","errorType":"exception","errorClass":"ZkException","httpStatus":null,"severity":"error","filePath":"common/src/main/java/com/alibaba/otter/canal/common/zookeeper/ZooKeeperx.java","lineNumber":117,"sourceCode":"                    String cluster = _serversList.get(i);\n                    // 强制获取zk中的地址信息\n                    ClientCnxn cnxn = (ClientCnxn) ReflectionUtils.getField(clientCnxnField, zk);\n                    HostProvider hostProvider = (HostProvider) ReflectionUtils.getField(hostProviderField, cnxn);\n                    List<InetSocketAddress> serverAddrs = (List<InetSocketAddress>) ReflectionUtils.getField(serverAddressesField,\n                        hostProvider);\n                    // 添加第二组集群列表\n                    serverAddrs.addAll(new ConnectStringParser(cluster).getServerAddresses());\n                }\n            }\n        } catch (Exception e) {\n            try {\n                if (zk != null) {\n                    zk.close();\n                }\n            } catch (InterruptedException ie) {\n                // ignore interrupt\n            }\n            throw new ZkException(\"zookeeper_create_error, serveraddrs=\" + cluster1, e);\n        }\n\n    }\n}\n","sourceCodeStart":99,"sourceCodeEnd":122,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/common/src/main/java/com/alibaba/otter/canal/common/zookeeper/ZooKeeperx.java#L99-L122","documentation":"Thrown by ZooKeeperx.configMutliCluster when merging additional ZK cluster address lists via reflection fails. configMutliCluster only runs when the connect string contains ';' (multi-cluster fallback). It reflectively appends a second cluster's InetSocketAddress list into the first ZooKeeper's HostProvider; any reflection or address-parse failure closes the zk handle and throws ZkException carrying the first cluster string. This usually indicates an incompatible ZooKeeper client version (reflection field names changed) or a malformed second-cluster connect string.","triggerScenarios":"canal.zkServers uses ';' to separate two clusters (e.g. 'a:2181;b:2181') and either (a) the bundled zookeeper.jar lacks the reflectively-accessed fields 'cnxn'/'hostProvider'/'serverAddresses' (version drift), or (b) the second cluster string is unparseable by ConnectStringParser.","commonSituations":"Upgrading zookeeper client jar changed ClientCnxn internals so ReflectionUtils.findField returns a field whose value shape differs; using a multi-region ZK failover config where the secondary cluster string is malformed; running a shaded/relocated zookeeper jar.","solutions":["Use a single ZK ensemble (no ';') if multi-cluster failover is not required — configMutliCluster returns early and the failure path is skipped.","Ensure the zookeeper client jar version matches the one canal was built/tested against (check pom dependency versions) so reflective fields exist.","Validate the second cluster connect string (host:port pairs, comma-separated) is syntactically correct.","If you need multi-cluster failover, pin the exact supported zookeeper version or avoid this proprietary multi-cluster feature."],"exampleFix":"# before\ncanal.zkServers = zk-hz-1:2181,zk-hz-2:2181;zk-us-1:2181,zk-us-2:notaport\n# after\ncanal.zkServers = zk-hz-1:2181,zk-hz-2:2181,zk-hz-3:2181","handlingStrategy":"validation","validationCode":"// Validate multi-cluster connect string shape before constructing ZooKeeperx\nvoid validateMultiCluster(String zkServers) {\n    if (zkServers == null || zkServers.trim().isEmpty()) {\n        throw new IllegalArgumentException(\"canal.zkServers is empty\");\n    }\n    for (String cluster : zkServers.split(\";\")) {\n        for (String hp : cluster.split(\",\")) {\n            String[] parts = hp.split(\":\");\n            if (parts.length != 2 || !parts[1].matches(\"\\\\d+\")) {\n                throw new IllegalArgumentException(\"bad ZK host:port \" + hp);\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    new ZooKeeperx(zkServers).connect(watcher);\n} catch (org.I0Itec.zkclient.exception.ZkException e) {\n    if (e.getMessage().startsWith(\"zookeeper_create_error\")) {\n        // multi-cluster merge failed: fall back to a single ensemble\n        new ZooKeeperx(firstClusterOnly(zkServers)).connect(watcher);\n    } else throw e;\n}","preventionTips":["Pin the zookeeper client jar version canal was built against to avoid reflective-field drift.","Prefer a single resilient ensemble over the ';' multi-cluster feature unless required.","Validate each ';' cluster segment parses to host:port pairs."],"tags":["zookeeper","multi-cluster","reflection","version-compat"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}