t8y2/dbx · error

start ZooKeeper DIGEST-MD5 negotiation: %w

Error message

start ZooKeeper DIGEST-MD5 negotiation: %w

What it means

negotiateSASLDigest begins a DIGEST-MD5 SASL handshake with ZooKeeper. This error wraps a failure returned by saslClient.Start(), i.e. the client could not even produce the initial authentication token — typically because the SASL credentials (username/password) are missing or malformed. It is raised before any round-trip with the server.

Source

Thrown at agents/drivers/zookeeper/sasl.go:92

type saslClient interface {
	Start() ([]byte, error)
	Step(challenge []byte) ([]byte, error)
	Complete() bool
}

func negotiateSASLDigest(connection net.Conn, timeout time.Duration, saslClient saslClient) error {
	if timeout <= 0 {
		timeout = defaultConnectionTimeout
	}
	if err := connection.SetDeadline(time.Now().Add(timeout)); err != nil {
		return err
	}
	defer connection.SetDeadline(time.Time{})

	token, err := saslClient.Start()
	if err != nil {
		return fmt.Errorf("start ZooKeeper DIGEST-MD5 negotiation: %w", err)
	}
	for round := 0; round < zooKeeperSASLMaxRounds; round++ {
		challenge, err := zooKeeperSASLRound(connection, zooKeeperSASLXIDBase+int32(round), token)
		if err != nil {
			return fmt.Errorf("ZooKeeper SASL round %d: %w", round+1, err)
		}
		if saslClient.Complete() {
			if len(challenge) != 0 {
				return errors.New("ZooKeeper sent an unexpected token after DIGEST-MD5 completion")
			}
			return nil
		}
		token, err = saslClient.Step(challenge)
		if err != nil {
			return fmt.Errorf("continue ZooKeeper DIGEST-MD5 negotiation at round %d: %w", round+1, err)
		}
		if saslClient.Complete() {
			if len(token) != 0 {

View on GitHub (pinned to c0390bff16)

Solutions

  1. Verify the SASL username and password supplied to authenticateSASLDigest are non-empty and correct.
  2. Check the server's zoo.cfg auth configuration accepts DIGEST-MD5 (authProvider.1 = org.apache.zookeeper.server.auth.DigestAuthenticationProvider).
  3. Inspect the wrapped inner error (%w) in logs to see the exact Start() failure.
  4. Confirm the SASL client library version matches the mechanism you configured.

Example fix

// before
connOpts := Options{Host: "zk:2181", SASL: true} // no credentials
// after
connOpts := Options{Host: "zk:2181", SASL: true, SASLUser: "admin", SASLPassword: "secret"}
Defensive patterns

Strategy: validation

Validate before calling

func saslCredsValid(user, pass string) bool { return user != "" && pass != "" }
if !saslCredsValid(opts.SASLUser, opts.SASLPassword) {
	return errors.New("SASL credentials required for DIGEST-MD5 auth")
}

Try / catch

if err := authenticateSASLDigest(conn, creds); err != nil {
	var inner error
	if errors.As(err, &inner) { log.Printf("SASL start failed: %v", inner) }
	return fmt.Errorf("sasl auth: %w", err)
}

Prevention

When it happens

Trigger: authenticateSASLDigest calls negotiateSASLDigest; the underlying saslClient.Start() returns an error (invalid or empty username/password, mis-initialized SASL client) and the error is wrapped with this message.

Common situations: Missing or empty digest username/password in connection config, wrong auth scheme selected for the server's mechanism, or building the SASL client with options it does not support.

Related errors


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