{"record":{"id":"f81a5b57da7b2e22","repo":"t8y2/dbx","slug":"zookeeper-sasl-client-is-nil-f81a5b","errorCode":null,"errorMessage":"ZooKeeper SASL client is nil","messagePattern":"ZooKeeper SASL client is nil","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/hive-go/zookeeper_protocol.go","lineNumber":195,"sourceCode":"\t\treturn nil, zk.ErrSessionExpired\n\t}\n\treturn client, nil\n}\n\nfunc zooKeeperTimeoutMillis(timeout time.Duration) int32 {\n\tmilliseconds := timeout.Milliseconds()\n\tif milliseconds < 1 {\n\t\treturn 1\n\t}\n\tif milliseconds > math.MaxInt32 {\n\t\treturn math.MaxInt32\n\t}\n\treturn int32(milliseconds)\n}\n\nfunc (client *protocolZooKeeperClient) authenticateSASL(saslClient zooKeeperSASLClient) error {\n\tif saslClient == nil {\n\t\treturn errors.New(\"ZooKeeper SASL client is nil\")\n\t}\n\tdefer saslClient.Dispose()\n\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)","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/hive-go/zookeeper_protocol.go#L177-L213","documentation":"authenticateSASL runs the GSSAPI/SASL handshake with the ZooKeeper server and requires a non-nil zooKeeperSASLClient to generate tokens. A nil SASL client means there is no negotiation implementation, so the function fails fast before attempting Start().","triggerScenarios":"Calling client.authenticateSASL(nil) or passing an uninitialized/typed-nil SASL client variable (e.g. a nil *kerberosSASLClient stored in an interface).","commonSituations":"Kerberos credentials failed to load so the SASL client constructor returned nil and the error was swallowed; a build without Kerberos support yields a nil client; test harness omits the client.","solutions":["Construct the SASL client with valid Kerberos credentials before calling authenticateSASL, and check its construction error","Avoid typed-nil interfaces: return (nil, err) or a real client, never a nil pointer stored in the interface","Ensure the Kerberos ticket/keytab is available in the environment (KRB5CCNAME, keytab path)","If authentication is not intended, use a non-SASL connect path instead of authenticateSASL"],"exampleFix":"// before\nvar sasl zooKeeperSASLClient // nil\nif err := client.authenticateSASL(sasl); err != nil { ... }\n// after\nsasl, err := newKerberosSASLClient(principal, keytab)\nif err != nil {\n    return fmt.Errorf(\"build SASL client: %w\", err)\n}\nif err := client.authenticateSASL(sasl); err != nil { ... }","handlingStrategy":"validation","validationCode":"// Go\nif saslClient == nil {\n    return errors.New(\"SASL client must be constructed with valid Kerberos credentials\")\n}\nif err := client.authenticateSASL(saslClient); err != nil { ... }","typeGuard":"// Go\nfunc hasSASL(c zooKeeperSASLClient) bool {\n    return c != nil // catches nil interface; also avoid storing typed nils\n}","tryCatchPattern":null,"preventionTips":["Construct SASL clients in one place and propagate construction errors","Never store a nil concrete pointer into an interface field","Gate authenticateSASL calls behind a Kerberos-config check"],"tags":["zookeeper","sasl","kerberos","go"],"backgroundTag":"sasl-authentication-required","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"}