{"record":{"id":"3f544888bf6109d6","repo":"t8y2/dbx","slug":"zookeeper-server-list-is-empty-3f5448","errorCode":null,"errorMessage":"ZooKeeper server list is empty","messagePattern":"ZooKeeper server list is empty","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/hive-go/zookeeper_protocol.go","lineNumber":93,"sourceCode":"\toptions.QOP = \"auth\"\n\toptions.AuthorizationID = \"\"\n\toptions.ServiceHost = \"\"\n\toptions.CanonicalizeHost = config.ZooKeeperKerberos.CanonicalHostname\n\toptions.ServerName = config.ZooKeeperKerberos.ServerPrincipal\n\tif options.ServerName == \"\" && config.ZooKeeperKerberos.Realm != \"\" {\n\t\toptions.ServerName = service + \"/_HOST@\" + config.ZooKeeperKerberos.Realm\n\t}\n\treturn service, options\n}\n\nfunc connectKerberosZooKeeper(\n\tservers []string,\n\ttimeout time.Duration,\n\ttlsConfig *tls.Config,\n\tconfig connectionConfig,\n) (zooKeeperClient, <-chan zk.Event, error) {\n\tif len(servers) == 0 {\n\t\treturn nil, nil, errors.New(\"ZooKeeper server list is empty\")\n\t}\n\tif !config.Kerberos.Enabled {\n\t\treturn nil, nil, errors.New(\"ZooKeeper Kerberos SASL requires Hive Kerberos credentials\")\n\t}\n\tordered := append([]string(nil), servers...)\n\tshuffleZooKeeperServers(ordered)\n\tvar failures []string\n\tfor _, address := range ordered {\n\t\thost, _, err := net.SplitHostPort(address)\n\t\tif err != nil {\n\t\t\tfailures = append(failures, fmt.Sprintf(\"%s: %v\", address, err))\n\t\t\tcontinue\n\t\t}\n\t\tconnection, err := dialZooKeeperConnection(address, timeout, tlsConfig)\n\t\tif err != nil {\n\t\t\tfailures = append(failures, fmt.Sprintf(\"%s: %v\", address, err))\n\t\t\tcontinue\n\t\t}","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/hive-go/zookeeper_protocol.go#L75-L111","documentation":"connectKerberosZooKeeper validates the server list before attempting any connection. An empty list means there is no ensemble member to dial, so the function fails fast with this error instead of shuffling and iterating zero hosts.","triggerScenarios":"Calling connectKerberosZooKeeper with servers == nil or len(servers)==0 — typically because the ZooKeeper discovery hosts string was empty or parsed to nothing.","commonSituations":"Connection string like zk= with no hosts; DNS/service-discovery returned no ZooKeeper endpoints; config key omitted entirely while Kerberos is enabled.","solutions":["Populate the ZooKeeper server list in the connection config (host1:2181,host2:2181,...)","Verify discovery/Helm/env config actually yields ZooKeeper endpoints before dialing","Add a caller-side precheck for len(servers) > 0 to produce a clearer config error","If hosts come from an upstream service, log the raw source value to see why it parsed empty"],"exampleFix":"// before\nzkHosts := os.Getenv(\"ZOOKEEPER_HOSTS\") // \"\"\nconn, err := connectKerberosZooKeeper(ctx, strings.Split(zkHosts, \",\"), timeout, tls, cfg)\n// after\nzkHosts := os.Getenv(\"ZOOKEEPER_HOSTS\")\nif zkHosts == \"\" {\n    return fmt.Errorf(\"ZOOKEEPER_HOSTS must be set\")\n}\nconn, err := connectKerberosZooKeeper(ctx, strings.Split(zkHosts, \",\"), timeout, tls, cfg)","handlingStrategy":"validation","validationCode":"hosts := parseZooKeeperHosts(cfg.ZooKeeperHosts)\nif len(hosts) == 0 {\n    return errors.New(\"at least one ZooKeeper host is required\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate the ZooKeeper hosts config at startup (fail fast)","Require the host list via env/config with a startup assertion","Log the raw hosts string when discovery yields an empty list"],"tags":["zookeeper","configuration","kerberos","empty-list"],"backgroundTag":"missing-config-value","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}