apache/pulsar · error · SaslException

Cannot create SASL client with empty JAAS subject principal

Error message

Cannot create SASL client with empty JAAS subject principal

What it means

PulsarSaslClient's constructor validates that the JAAS Subject used as the client identity has at least one Principal; an empty principal set means the subject carries no authenticated identity (no Kerberos user), so the GSSAPI mechanism cannot be built. It throws SaslException with this message.

Source

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

 * This is added for support Kerberos authentication.
 */
@CustomLog
public class PulsarSaslClient {
    private final SaslClient saslClient;
    private final Subject clientSubject;

    public PulsarSaslClient(String serverHostname, String serverType, Subject subject) throws SaslException {
        checkArgument(subject != null, "Cannot create SASL client with NULL JAAS subject");
        checkArgument(!Strings.isNullOrEmpty(serverHostname), "Cannot create SASL client with NUll server name");
        if (!serverType.equals(SaslConstants.SASL_BROKER_PROTOCOL) && !serverType
                                                                           .equals(SaslConstants.SASL_PROXY_PROTOCOL)) {
            log.warn().attr("serverType", serverType).log("The server type is not recommended");
        }

        String serverPrincipal = serverType.toLowerCase() + "/" + serverHostname;
        this.clientSubject = subject;
        if (clientSubject.getPrincipals().isEmpty()) {
            throw new SaslException("Cannot create SASL client with empty JAAS subject principal");
        }
        // GSSAPI/Kerberos
        final Object[] principals = clientSubject.getPrincipals().toArray();
        final Principal clientPrincipal = (Principal) principals[0];

        final KerberosName clientKerberosName = new KerberosName(clientPrincipal.getName());
        KerberosName serviceKerberosName = new KerberosName(serverPrincipal + "@" + clientKerberosName.getRealm());
        final String serviceName = serviceKerberosName.getServiceName();
        final String serviceHostname = serviceKerberosName.getHostName();
        final String clientPrincipalName = clientKerberosName.toString();
        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"};

View on GitHub (pinned to 820761864e)

Solutions

  1. Verify the JAAS login actually produces a principal: after LoginContext.login(), assert !subject.getPrincipals().isEmpty() before constructing PulsarSaslClient.
  2. Fix the JAAS config file: ensure the section (default PulsarClient) uses com.sun.security.auth.module.Krb5LoginModule with required/ sufficient flag and a valid keyTab/principal.
  3. Confirm the keytab exists and is readable, and that kinit/klist shows valid credentials.
  4. Check that login failure isn't being swallowed — JAAS modules with optional flag won't throw but yield an empty subject.

Example fix

// before
Subject subject = new Subject(); // empty, no login performed
PulsarSaslClient client = new PulsarSaslClient(host, "broker", subject); // SaslException
// after
LoginContext lc = new LoginContext("PulsarClient");
lc.login();
Subject subject = lc.getSubject();
if (subject.getPrincipals().isEmpty()) { throw new IllegalStateException("JAAS login produced no principal"); }
PulsarSaslClient client = new PulsarSaslClient(host, "broker", subject);
Defensive patterns

Strategy: validation

Validate before calling

// Java: verify the JAAS subject has principals before constructing PulsarSaslClient
static void validateSubject(Subject subject) {
    if (subject == null || subject.getPrincipals().isEmpty()) {
        throw new IllegalStateException("JAAS subject has no principals; login failed or was skipped");
    }
}

Try / catch

try {
    PulsarSaslClient client = new PulsarSaslClient(host, serverType, subject);
} catch (SaslException e) {
    if (e.getMessage().contains("empty JAAS subject principal")) {
        throw new IllegalStateException("Kerberos login produced no principal — check JAAS config and kinit", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Constructing PulsarSaslClient with a Subject produced by a failed or no-op JAAS login — e.g. the LoginContext logged in a subject with no principals because the Krb5LoginModule was skipped (useKeyTab=false with no ticket, debug misconfig) or the login silently produced an empty subject.

Common situations: Kerberos keytab path wrong or unreadable so login falls through without a principal; JAAS section misconfigured (wrong principal/debug flags) causing login to succeed with zero principals; passing new Subject() or a subject created without doAsPrivileged login; expired TGT combined with a module configured not to fail.

Related errors


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