{"record":{"id":"7ba541751ea481de","repo":"t8y2/dbx","slug":"zookeeper-sasl-round-d-w","errorCode":null,"errorMessage":"ZooKeeper SASL round %d: %w","messagePattern":"ZooKeeper SASL round (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/argo-go/zookeeper_protocol.go","lineNumber":211,"sourceCode":"func (client *protocolZooKeeperClient) authenticateSASL(saslClient zooKeeperSASLClient) error {\n\tif saslClient == nil {\n\t\treturn errors.New(\"ZooKeeper SASL client is nil\")\n\t}\n\tdefer saslClient.Dispose()\n\ttoken, err := saslClient.Start()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"start ZooKeeper GSSAPI negotiation: %w\", err)\n\t}\n\tfor round := 0; round < zooKeeperMaxSASLRounds; round++ {\n\t\tresponse, requestErr := client.request(zooKeeperOpSASL, func(encoder *zooKeeperEncoder) {\n\t\t\tif token == nil {\n\t\t\t\tencoder.bytes([]byte{})\n\t\t\t\treturn\n\t\t\t}\n\t\t\tencoder.bytes(token)\n\t\t})\n\t\tif requestErr != nil {\n\t\t\treturn fmt.Errorf(\"ZooKeeper SASL round %d: %w\", round+1, requestErr)\n\t\t}\n\t\tdecoder := newZooKeeperDecoder(response)\n\t\tchallenge, decodeErr := decoder.bytes()\n\t\tif decodeErr != nil {\n\t\t\treturn fmt.Errorf(\"decode ZooKeeper SASL round %d: %w\", round+1, decodeErr)\n\t\t}\n\t\tif saslClient.Complete() {\n\t\t\tif len(challenge) != 0 {\n\t\t\t\treturn errors.New(\"ZooKeeper sent an unexpected token after GSSAPI completion\")\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\ttoken, err = saslClient.Step(challenge)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"continue ZooKeeper GSSAPI negotiation at round %d: %w\", round+1, err)\n\t\t}\n\t}\n\treturn fmt.Errorf(\"ZooKeeper GSSAPI negotiation exceeded %d rounds\", zooKeeperMaxSASLRounds)","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/argo-go/zookeeper_protocol.go#L193-L229","documentation":"This error wraps any failure that occurs while sending or receiving a ZooKeeper SASL (GSSAPI/Kerberos) round-trip during authentication. authenticateSASL sends each GSSAPI token via a SASL opcode request; if the underlying request fails (I/O error, timeout, protocol error, auth failure), it is wrapped with the SASL round number so the failing negotiation step is identifiable. It indicates the client never got a usable challenge/response for that round.","triggerScenarios":"Calling any ZooKeeper operation that triggers authenticateSASL (connection setup with a SASL/GSSAPI client) where client.request(zooKeeperOpSASL, ...) returns an error on a given round: TCP write/read failure, read/write deadline (client.timeout) exceeded, server closing the connection mid-negotiation, or a ZooKeeper error code returned in the response (e.g. auth failure).","commonSituations":"Kerberos environment misconfiguration (missing/invalid keytab, wrong principal, stale ticket cache, KDC unreachable), ZooKeeper server rejecting the SASL token (server not configured with quorum.auth/sasl enabled), network/firewall dropping the connection mid-handshake, or timeouts set too low for the KDC round-trips.","solutions":["Verify the Kerberos environment on the client host: run kinit with the correct principal and confirm the ticket is valid (klist) before connecting.","Check the ZooKeeper server is configured for SASL (authProvider, jaas.conf) and the client principal is allowed by the server ACL; inspect the server log for the matching auth failure.","Increase the client timeout passed to the ZooKeeper connection so SASL/KDC round-trips are not cut off by the read/write deadline.","Test network reachability to the ZooKeeper quorum (the error wraps raw I/O errors; connection resets indicate firewall/proxy drops).","Inspect the wrapped inner error (%w) to distinguish transport failure from a server-returned ZooKeeper error code."],"exampleFix":"// before: SASL fails due to missing ticket\nclient, err := zookeeper.Connect(hosts, timeout) // SASL round 1: read tcp ...: connection reset\n// after: kinit first and verify\n$ kinit -kt /etc/security/keytabs/zk.service.keytab zookeeper/host@REALM && klist\nclient, err := zookeeper.Connect(hosts, timeout)","handlingStrategy":"retry","validationCode":"// Validate Kerberos environment before connecting\nout, err := exec.Command(\"klist\", \"-s\").Output()\nif err != nil {\n    return fmt.Errorf(\"no valid Kerberos ticket; run kinit before connecting: %w\", err)\n}\nconn, err := net.DialTimeout(\"tcp\", host, 5*time.Second)\nif err != nil {\n    return fmt.Errorf(\"ZooKeeper host unreachable: %w\", err)\n}\nconn.Close()","typeGuard":null,"tryCatchPattern":"if err := client.Connect(); err != nil {\n    var saslErr error\n    if strings.Contains(err.Error(), \"ZooKeeper SASL round\") && errors.As(err, &saslErr) {\n        if isRetryable(err) { // transport timeout/reset, not auth rejection\n            time.Sleep(backoff)\n            return retryConnect()\n        }\n    }\n    return fmt.Errorf(\"zookeeper connect failed: %w\", err)\n}","preventionTips":["Run a scheduled kinit (or use a keytab with kinit -kt) so tickets never expire while the process runs.","Verify the ZooKeeper server's SASL/JAAS configuration before deploying the client.","Set the connection timeout generously enough to cover multiple KDC round-trips.","Confirm network paths and firewall rules to port 2181 allow sustained TCP sessions."],"tags":["go","zookeeper","sasl","kerberos","authentication","network"],"backgroundTag":"sasl-authentication-failed","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}