t8y2/dbx · error

ZooKeeper SASL round %d: %w

Error message

ZooKeeper SASL round %d: %w

What it means

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.

Source

Thrown at agents/drivers/argo-go/zookeeper_protocol.go:211

func (client *protocolZooKeeperClient) authenticateSASL(saslClient zooKeeperSASLClient) error {
	if saslClient == nil {
		return errors.New("ZooKeeper SASL client is nil")
	}
	defer saslClient.Dispose()
	token, err := saslClient.Start()
	if err != nil {
		return fmt.Errorf("start ZooKeeper GSSAPI negotiation: %w", err)
	}
	for round := 0; round < zooKeeperMaxSASLRounds; round++ {
		response, requestErr := client.request(zooKeeperOpSASL, func(encoder *zooKeeperEncoder) {
			if token == nil {
				encoder.bytes([]byte{})
				return
			}
			encoder.bytes(token)
		})
		if requestErr != nil {
			return fmt.Errorf("ZooKeeper SASL round %d: %w", round+1, requestErr)
		}
		decoder := newZooKeeperDecoder(response)
		challenge, decodeErr := decoder.bytes()
		if decodeErr != nil {
			return fmt.Errorf("decode ZooKeeper SASL round %d: %w", round+1, decodeErr)
		}
		if saslClient.Complete() {
			if len(challenge) != 0 {
				return errors.New("ZooKeeper sent an unexpected token after GSSAPI completion")
			}
			return nil
		}
		token, err = saslClient.Step(challenge)
		if err != nil {
			return fmt.Errorf("continue ZooKeeper GSSAPI negotiation at round %d: %w", round+1, err)
		}
	}
	return fmt.Errorf("ZooKeeper GSSAPI negotiation exceeded %d rounds", zooKeeperMaxSASLRounds)

View on GitHub (pinned to c0390bff16)

Solutions

  1. Verify the Kerberos environment on the client host: run kinit with the correct principal and confirm the ticket is valid (klist) before connecting.
  2. 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.
  3. Increase the client timeout passed to the ZooKeeper connection so SASL/KDC round-trips are not cut off by the read/write deadline.
  4. Test network reachability to the ZooKeeper quorum (the error wraps raw I/O errors; connection resets indicate firewall/proxy drops).
  5. Inspect the wrapped inner error (%w) to distinguish transport failure from a server-returned ZooKeeper error code.

Example fix

// before: SASL fails due to missing ticket
client, err := zookeeper.Connect(hosts, timeout) // SASL round 1: read tcp ...: connection reset
// after: kinit first and verify
$ kinit -kt /etc/security/keytabs/zk.service.keytab zookeeper/host@REALM && klist
client, err := zookeeper.Connect(hosts, timeout)
Defensive patterns

Strategy: retry

Validate before calling

// Validate Kerberos environment before connecting
out, err := exec.Command("klist", "-s").Output()
if err != nil {
    return fmt.Errorf("no valid Kerberos ticket; run kinit before connecting: %w", err)
}
conn, err := net.DialTimeout("tcp", host, 5*time.Second)
if err != nil {
    return fmt.Errorf("ZooKeeper host unreachable: %w", err)
}
conn.Close()

Try / catch

if err := client.Connect(); err != nil {
    var saslErr error
    if strings.Contains(err.Error(), "ZooKeeper SASL round") && errors.As(err, &saslErr) {
        if isRetryable(err) { // transport timeout/reset, not auth rejection
            time.Sleep(backoff)
            return retryConnect()
        }
    }
    return fmt.Errorf("zookeeper connect failed: %w", err)
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05). Data as JSON: /api/errors/7ba541751ea481de. Report an issue: GitHub.