t8y2/dbx · error
ZooKeeper sent an unexpected token after GSSAPI completion
Error message
ZooKeeper sent an unexpected token after GSSAPI completion
What it means
During authenticateSASL, once the local GSSAPI client reports Complete(), the server must send no further SASL token. If an additional non-empty challenge arrives after completion, the protocol state is inconsistent and the client returns this error rather than feeding the completed negotiator another token.
Source
Thrown at agents/drivers/argo-go/zookeeper_protocol.go:220
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)
}
func (client *protocolZooKeeperClient) AddAuth(scheme string, auth []byte) error {
_, err := client.request(zooKeeperOpSetAuth, func(encoder *zooKeeperEncoder) {
encoder.int32(0)
encoder.string(scheme)
encoder.bytes(auth)
})
return errView on GitHub (pinned to c0390bff16)
Solutions
- Verify you are connecting directly to a supported ZooKeeper version and not through a packet-rewriting proxy
- Ensure client and server SASL configurations match (quorum.auth / server.auth settings)
- Capture the exchange (packet logs) and check whether the extra token is a duplicated frame
- Retry the connection — a transient desync in one session may not recur; if persistent, align server/client versions
Defensive patterns
Strategy: retry
Validate before calling
// no caller-side check; ensure direct connectivity to a supported ZooKeeper version
if viaProxy {
log.Warn("SASL through proxies can produce extra tokens; connect directly if possible")
} Try / catch
err := zkClient.authenticateSASL(sasl)
if err != nil && strings.Contains(err.Error(), "unexpected token after GSSAPI completion") {
// retry once with a fresh connection; if persistent, audit server/proxy SASL config
} Prevention
- Connect directly to the ensemble, avoiding packet-rewriting proxies/LBs
- Keep ZooKeeper server and client protocol versions aligned
- Match client/server SASL (quorum.auth/server.auth) configuration
- Capture packet traces when the error recurs to identify duplicated frames
When it happens
Trigger: A misbehaving or non-conformant ZooKeeper server (or a proxy/interposer) sends an extra SASL challenge after the GSSAPI exchange finished; decoding a stale/duplicated SASL response frame; protocol version mismatch causing frame desynchronization.
Common situations: Connecting through a load balancer or proxy that replays buffered packets; ZooKeeper server versions with buggy SASL handling; mixed client/server SASL quorum settings causing spurious rounds.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- ZooKeeper GSSAPI negotiation exceeded %d rounds
- ZooKeeper sent an unexpected token after GSSAPI completion
- decode ZooKeeper SASL round %d: %w
- continue ZooKeeper GSSAPI negotiation at round %d: %w
- ZooKeeper session closed because SASL authentication is requ
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/06f18c79346175da.
Report an issue: GitHub.