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
- Verify the SASL username and password supplied to authenticateSASLDigest are non-empty and correct.
- Check the server's zoo.cfg auth configuration accepts DIGEST-MD5 (authProvider.1 = org.apache.zookeeper.server.auth.DigestAuthenticationProvider).
- Inspect the wrapped inner error (%w) in logs to see the exact Start() failure.
- 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
- Validate SASL username/password are non-empty before dialing.
- Keep credentials in env/secret manager and verify they load correctly at startup.
- Smoke-test SASL auth against a staging ZooKeeper with the same JAAS config.
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
- continue ZooKeeper DIGEST-MD5 negotiation at round %d: %w
- ZooKeeper session closed because SASL authentication is requ
- ZooKeeper authentication failed
- ZooKeeper session closed because SASL authentication is requ
- username is required when auth_scheme = "sasl_digest"
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/3cea914c1181125f.
Report an issue: GitHub.