apache/pulsar · error · SaslException

Cannot create JVM SASL Client

Error message

Cannot create JVM SASL Client

What it means

During construction, PulsarSaslClient asks the JVM (Sasl.createSaslClient with the GSSAPI mechanism, inside Subject.doAs) to build a SASL client for Kerberos authentication. If the JVM returns null instead of a SaslClient — meaning no provider could supply GSSAPI — this SaslException is thrown. It is distinct from 'error while booting GSSAPI client' (which wraps an actual exception); here the factory silently failed to create anything.

Source

Thrown at pulsar-client-auth-sasl/src/main/java/org/apache/pulsar/client/impl/auth/PulsarSaslClient.java:89

        log.info().attr("serverPrincipal", serverPrincipal)
                .log("Using JAAS/SASL/GSSAPI auth to connect to server");

        try {
            this.saslClient = Subject.doAs(clientSubject, new PrivilegedExceptionAction<SaslClient>() {
                @Override
                public SaslClient run() throws SaslException {
                    String[] mechs = {"GSSAPI"};
                    return Sasl.createSaslClient(mechs, clientPrincipalName, serviceName, serviceHostname, null,
                        new ClientCallbackHandler());
                }
            });
        } catch (PrivilegedActionException err) {
            log.error().exception(err.getCause()).log("GSSAPI client error");
            throw new SaslException("error while booting GSSAPI client", err.getCause());
        }

        if (saslClient == null) {
            throw new SaslException("Cannot create JVM SASL Client");
        }

    }

    public AuthData evaluateChallenge(final AuthData saslToken) throws AuthenticationException {
        if (saslToken == null) {
            throw new AuthenticationException("saslToken is null");
        }
        try {
            if (clientSubject != null) {
                final byte[] retval = Subject.doAs(clientSubject, new PrivilegedExceptionAction<byte[]>() {
                    @Override
                    public byte[] run() throws SaslException {
                        return saslClient.evaluateChallenge(saslToken.getBytes());
                    }
                });
                return AuthData.of(retval);

View on GitHub (pinned to 820761864e)

Solutions

  1. Ensure the JVM includes the SASL/GSSAPI provider: use a full JDK or a JRE containing com.sun.security.sasl provider and confirm 'GSSAPI' support in the provider list
  2. Check the java.security file (JRE/lib/security/java.security) so the standard security providers (SUN, SunJGSS, SunSASL, etc.) are not removed or reordered
  3. Add or restore the provider programmatically if removed: Security.addProvider(new com.sun.security.sasl.Provider()) equivalent / fix security.provider.N entries
  4. Log/debug the SASL provider resolution (Sasl.getSaslClientFactories()) in the target container to confirm GSSAPI factories are visible to the client app
  5. Verify runtime matches the environment used in testing (container base image may use a slim JRE without SASL)

Example fix

// before: failing on a slim JRE without SASL provider
PulsarSaslClient client = new PulsarSaslClient(host, "broker", jaasSubject);

// after: ensure providers are present at startup
import com.sun.security.sasl.Provider;
if (java.security.Security.getProvider("SunSASL") == null) {
    java.security.Security.addProvider(new Provider());
}
PulsarSaslClient client = new PulsarSaslClient(host, "broker", jaasSubject);
Defensive patterns

Strategy: validation

Validate before calling

// before creating PulsarSaslClient
if (java.security.Security.getProvider("SunSASL") == null
        && java.security.Security.getProviders("SaslClientFactory.GSSAPI").length == 0) {
    throw new IllegalStateException("No SASL provider with GSSAPI support on this JVM");
}

Type guard

boolean gssapiAvailable() {
    try {
        return javax.security.sasl.Sasl.createSaslClient(
                new String[]{"GSSAPI"}, null, "dummy", "dummy", null, null) != null;
    } catch (Exception e) {
        return false;
    }
}

Prevention

When it happens

Trigger: Calling new PulsarSaslClient(serverHostname, serverType, subject) when Sasl.createSaslClient(new String[]{"GSSAPI"}, ...) returns null — i.e. no installed SASL provider implements GSSAPI for the given mechanism/service/hostname combination.

Common situations: Running on a JRE (not JDK) or a stripped runtime without the com.sun.security.sasl.provider; security provider list (java.security) modified so GSSAPI-supporting providers are removed or ordered out; using a custom SASL provider setup in a container; name a JRE that lacks the SASL implementation classes.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/f542dfc64a83a71a. Report an issue: GitHub.