t8y2/dbx · error
parse ZooKeeper TLS address %q: %w
Error message
parse ZooKeeper TLS address %q: %w
What it means
Wrapped during a TLS connection to a ZooKeeper ensemble: when the tls.Config has no explicit ServerName, the client derives it from the address via net.SplitHostPort. If the address is malformed (no host:port, brackets wrong, extra characters), SplitHostPort fails and the dial aborts with this error. It surfaces the underlying parse error plus the offending address string.
Source
Thrown at agents/drivers/argo-go/zookeeper_protocol.go:59
var newZooKeeperSASLClient = func(host string, config connectionConfig) (zooKeeperSASLClient, error) {
service, options := zooKeeperGSSAPIOptions(config)
mechanism, err := gosasl.NewGSSAPIMechanismWithOptions(service, options)
if err != nil {
return nil, err
}
return gosasl.NewSaslClient(host, mechanism), nil
}
var dialZooKeeperConnection = func(address string, timeout time.Duration, tlsConfig *tls.Config) (net.Conn, error) {
dialer := &net.Dialer{Timeout: timeout}
if tlsConfig == nil {
return dialer.Dial("tcp", address)
}
config := tlsConfig.Clone()
if config.ServerName == "" {
host, _, err := net.SplitHostPort(address)
if err != nil {
return nil, fmt.Errorf("parse ZooKeeper TLS address %q: %w", address, err)
}
config.ServerName = host
}
return tls.DialWithDialer(dialer, "tcp", address, config)
}
var shuffleZooKeeperServers = func(servers []string) {
rand.Shuffle(len(servers), func(first, second int) {
servers[first], servers[second] = servers[second], servers[first]
})
}
func zooKeeperGSSAPIOptions(config connectionConfig) (string, gosasl.GSSAPIOptions) {
service := firstNonEmpty(config.ZooKeeperKerberos.Service, "zookeeper")
options := gssapiOptionsFromKerberos(config.Kerberos)
options.QOP = "auth"
options.AuthorizationID = ""
options.ServiceHost = ""View on GitHub (pinned to c0390bff16)
Solutions
- Correct the address to valid 'host:port' form (e.g. 'zk1.example.com:2181', '[2001:db8::1]:2181')
- If the config intentionally omits the port, append the default ZooKeeper port 2181 before dialing
- Alternatively set tlsConfig.ServerName explicitly in code so the SplitHostPort fallback is skipped
- Validate addresses with net.SplitHostPort at config load time and fail early with a clear message
Example fix
// before
address := "zk1.example.com"
conn, err := tlsConnect(address)
// after
address := "zk1.example.com:2181"
if _, _, err := net.SplitHostPort(address); err != nil {
return fmt.Errorf("invalid ZooKeeper address %q: %w", address, err)
}
conn, err := tlsConnect(address) Defensive patterns
Strategy: validation
Validate before calling
func validZKAddress(addr string) error {
_, _, err := net.SplitHostPort(addr)
return err
} Type guard
func isHostPort(s string) bool {
host, port, err := net.SplitHostPort(s)
return err == nil && host != "" && port != ""
} Try / catch
conn, err := tlsConnect(address)
if err != nil {
var parseErr *net.AddrError
if errors.As(err, &parseErr) && parseErr.Err == "missing port in address" {
address = net.JoinHostPort(strings.TrimSuffix(address, ":"), "2181")
conn, err = tlsConnect(address)
}
if err != nil { return err }
} Prevention
- Always store ZooKeeper endpoints as host:port, validated at config load with net.SplitHostPort
- Use net.JoinHostPort to build addresses (handles IPv6 brackets)
- Set tlsConfig.ServerName explicitly to skip the address parsing fallback
- Test TLS connectivity to the ensemble during deployment smoke checks
When it happens
Trigger: Calling the TLS dial path in zookeeper_protocol.go with an address string that net.SplitHostPort cannot parse — e.g. missing port ('zk1:'), an empty string, an unbalanced IPv6 literal ('[::1'), or a host containing stray characters before TLS dial when config.ServerName is empty.
Common situations: ZooKeeper connect string assembled by hand or from a misparsed config value; trimming the port accidentally when substituting hosts; IPv6 ensemble addresses not bracketed; environment variable containing a bare hostname without ':2181'.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- ZooKeeper connection event: %w
- ZooKeeper connection timed out before a session was establis
- ZooKeeper session expired during connection
- JKS truststore contains no certificates
- PEM truststore contains no certificates
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/6bd5d97f100e1ae3.
Report an issue: GitHub.