{"record":{"id":"7c11b94be08e4efa","repo":"apache/pulsar","slug":"sasltoken-is-null","errorCode":null,"errorMessage":"saslToken is null","messagePattern":"saslToken is null","errorType":"exception","errorClass":"AuthenticationException","httpStatus":null,"severity":"error","filePath":"pulsar-client-auth-sasl/src/main/java/org/apache/pulsar/client/impl/auth/PulsarSaslClient.java","lineNumber":96,"sourceCode":"                    String[] mechs = {\"GSSAPI\"};\n                    return Sasl.createSaslClient(mechs, clientPrincipalName, serviceName, serviceHostname, null,\n                        new ClientCallbackHandler());\n                }\n            });\n        } catch (PrivilegedActionException err) {\n            log.error().exception(err.getCause()).log(\"GSSAPI client error\");\n            throw new SaslException(\"error while booting GSSAPI client\", err.getCause());\n        }\n\n        if (saslClient == null) {\n            throw new SaslException(\"Cannot create JVM SASL Client\");\n        }\n\n    }\n\n    public AuthData evaluateChallenge(final AuthData saslToken) throws AuthenticationException {\n        if (saslToken == null) {\n            throw new AuthenticationException(\"saslToken is null\");\n        }\n        try {\n            if (clientSubject != null) {\n                final byte[] retval = Subject.doAs(clientSubject, new PrivilegedExceptionAction<byte[]>() {\n                    @Override\n                    public byte[] run() throws SaslException {\n                        return saslClient.evaluateChallenge(saslToken.getBytes());\n                    }\n                });\n                return AuthData.of(retval);\n\n            } else {\n                return AuthData.of(saslClient.evaluateChallenge(saslToken.getBytes()));\n            }\n        } catch (Exception e) {\n            log.error().exception(e.getCause()).log(\"SASL error\");\n            throw new AuthenticationException(\"SASL/JAAS error\" + e.getCause());\n        }","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-auth-sasl/src/main/java/org/apache/pulsar/client/impl/auth/PulsarSaslClient.java#L78-L114","documentation":"PulsarSaslClient.evaluateChallenge(saslToken) requires the server-provided SASL challenge bytes wrapped in an AuthData object. When the caller passes null, the method immediately throws this AuthenticationException. This is a defensive argument check — the SASL protocol expects each challenge from the broker to carry a token.","triggerScenarios":"Calling evaluateChallenge(null) directly; an Authentication/AuthenticationDataProvider path that produces a null AuthData for a challenge step; wiring a custom Authentication implementation into the SASL flow that returns null on some handshake stage.","commonSituations":"Custom auth plugin integration where authenticate()/getAuthData returns null before delegating to PulsarSaslClient; broker sends an empty/unexpected challenge and the client-side adapter maps it to null; unit tests invoking evaluateChallenge directly without constructing AuthData.","solutions":["Ensure every challenge passed to evaluateChallenge is a non-null AuthData (e.g. AuthData.INIT from the client for the first step)","Inspect the Authentication/AuthenticationDataProvider implementation feeding the token; fix code paths that return null","If the broker sent no token, verify broker-side SASL configuration and the client's authParams (JAAS subject) are consistent","For custom plugins, default the first token to AuthData.of(new byte[0]) or AuthData.INIT rather than null"],"exampleFix":"// before\nauthData = saslClient.evaluateChallenge(challenge); // challenge may be null\n\n// after\nauthData = saslClient.evaluateChallenge(challenge == null ? AuthData.INIT : challenge);","handlingStrategy":"validation","validationCode":"// before calling evaluateChallenge\nif (saslToken == null) {\n    throw new IllegalArgumentException(\"SASL challenge token must not be null; use AuthData.INIT for the first step\");\n}\nAuthData resp = saslClient.evaluateChallenge(saslToken);","typeGuard":"boolean isValidAuthData(AuthData d) {\n    return d != null && d.getBytes() != null;\n}","tryCatchPattern":null,"preventionTips":["Always bootstrap the SASL exchange with AuthData.INIT or an empty AuthData, never null","Audit custom Authentication implementations for null-returning getAuthData paths","Unit-test the full challenge sequence (init -> challenge -> response) against a stubbed broker"],"tags":["sasl","authentication","null-argument"],"backgroundTag":"null-auth-token","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}