{"record":{"id":"a794ce8122570120","repo":"t8y2/dbx","slug":"decode-zookeeper-sasl-round-d-w","errorCode":null,"errorMessage":"decode ZooKeeper SASL round %d: %w","messagePattern":"decode ZooKeeper SASL round (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/argo-go/zookeeper_protocol.go","lineNumber":216,"sourceCode":"\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)\n}\n\nfunc (client *protocolZooKeeperClient) AddAuth(scheme string, auth []byte) error {\n\t_, err := client.request(zooKeeperOpSetAuth, func(encoder *zooKeeperEncoder) {\n\t\tencoder.int32(0)","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/argo-go/zookeeper_protocol.go#L198-L234","documentation":"This error occurs when the client cannot decode the SASL challenge bytes from a ZooKeeper SASL response frame. After each SASL request, authenticateSASL parses the reply expecting a length-prefixed token (the GSSAPI challenge); a decode failure means the response payload is shorter or malformed relative to the expected wire format. It usually signals a protocol mismatch or a corrupt/abridged response.","triggerScenarios":"During authenticateSASL, decoder.bytes() on the response of a zooKeeperOpSASL request fails because the response payload contains fewer bytes than its declared length prefix or is empty — e.g. an incompatible ZooKeeper server version, a proxy that truncates frames, or a server replying with an unexpected error body instead of a SASL token.","commonSituations":"Connecting through a load balancer/proxy that mangles ZooKeeper frames, mismatched ZooKeeper server protocol (older server not supporting the SASL opcode body format the client expects), or corrupted responses when the connection state desyncs after a prior failed request on the same TCP connection.","solutions":["Read the wrapped inner decode error to see whether the frame length exceeds the payload (truncation) — then check for proxies/NAT in front of ZooKeeper and connect directly to the quorum.","Confirm the ZooKeeper server version supports the SASL opcode with the same framing the client implements; upgrade the server or the client driver to matching versions.","Close and re-establish the connection: a desynced TCP stream after an earlier failure will keep producing malformed frames.","Check server logs for errors around the SASL round to see what the server actually replied.","Retry with a longer timeout in case a partial read due to a short deadline produced a short frame."],"exampleFix":"// before: proxy strips frames\nconnectErr := connect(\"zk-lb.internal:2181\") // decode ZooKeeper SASL round 1: unexpected EOF\n// after: connect directly to quorum members\nconnectErr := connect(\"zk-1.internal:2181,zk-2.internal:2181,zk-3.internal:2181\")","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := client.Get(path)\nif err != nil && strings.Contains(err.Error(), \"decode ZooKeeper SASL round\") {\n    // malformed frame — stream may be corrupt; do NOT reuse the connection\n    client.Close()\n    return redialAndRetry(path, 1)\n}\nreturn err","preventionTips":["Connect directly to ZooKeeper quorum members instead of through proxies that can truncate frames.","Use matching client/server driver versions supporting the same SASL framing.","Redial after any framing/decode error instead of continuing on a desynced stream.","Monitor for repeated decode failures from one endpoint — a sign of a broken middlebox."],"tags":["go","zookeeper","sasl","protocol","decoding"],"backgroundTag":"protocol-decode-failed","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}