apache/kafka · error · KafkaException
Principal has name with unexpected format ${servicePrincipal
Error message
Principal has name with unexpected format ${servicePrincipal} What it means
Thrown by SaslChannelBuilder.maybeAddNativeGssapiCredentials as a KafkaException when KerberosName.parse(servicePrincipal) raises IllegalArgumentException. This path runs only on the server side when sun.security.jgss.native=true and the subject has a GSSAPI/Kerberos principal but no GSSCredential; the code needs to parse the principal into primary/instance@REALM form to build a native GSS acceptor credential. A principal that does not match the expected Kerberos format cannot be turned into an acceptor name, so the broker aborts startup rather than silently failing client auth.
Source
Thrown at clients/src/main/java/org/apache/kafka/common/network/SaslChannelBuilder.java:382
}
}
// As described in http://docs.oracle.com/javase/8/docs/technotes/guides/security/jgss/jgss-features.html:
// "To enable Java GSS to delegate to the native GSS library and its list of native mechanisms,
// set the system property "sun.security.jgss.native" to true"
// "In addition, when performing operations as a particular Subject, for example, Subject.doAs(...)
// or Subject.doAsPrivileged(...), the to-be-used GSSCredential should be added to Subject's
// private credential set. Otherwise, the GSS operations will fail since no credential is found."
private void maybeAddNativeGssapiCredentials(Subject subject) {
boolean usingNativeJgss = Boolean.getBoolean(GSS_NATIVE_PROP);
if (usingNativeJgss && subject.getPrivateCredentials(GSSCredential.class).isEmpty()) {
final String servicePrincipal = SaslClientAuthenticator.firstPrincipal(subject);
KerberosName kerberosName;
try {
kerberosName = KerberosName.parse(servicePrincipal);
} catch (IllegalArgumentException e) {
throw new KafkaException("Principal has name with unexpected format " + servicePrincipal);
}
final String servicePrincipalName = kerberosName.serviceName();
final String serviceHostname = kerberosName.hostName();
try {
GSSManager manager = gssManager();
// This Oid is used to represent the Kerberos version 5 GSS-API mechanism. It is defined in
// RFC 1964.
Oid krb5Mechanism = new Oid("1.2.840.113554.1.2.2");
GSSName gssName = manager.createName(servicePrincipalName + "@" + serviceHostname, GSSName.NT_HOSTBASED_SERVICE);
GSSCredential cred = manager.createCredential(gssName,
GSSContext.INDEFINITE_LIFETIME, krb5Mechanism, GSSCredential.ACCEPT_ONLY);
subject.getPrivateCredentials().add(cred);
log.info("Configured native GSSAPI private credentials for {}@{}", serviceHostname, serviceHostname);
} catch (GSSException ex) {
log.warn("Cannot add private credential to subject; clients authentication may fail", ex);
}
}View on GitHub (pinned to c31c9215e1)
Solutions
- Set the JAAS principal to a fully-qualified Kerberos name of the form service/hostname@REALM (e.g. kafka/broker1.example.com@EXAMPLE.COM).
- Confirm the realm suffix matches the KDC and that the principal exists in the KDC (kinit and kvno succeed).
- If you did not intend to use native GSS, remove -Dsun.security.jgss.native=true so the pure-Java path (which does not call this parser) is used.
- Re-run with the corrected JAAS config and restart the broker.
Example fix
// before
KafkaServer {
com.sun.security.auth.module.Krb5LoginModule required
principal="kafka";
};
// after
KafkaServer {
com.sun.security.auth.module.Krb5LoginModule required
principal="kafka/broker1.example.com@EXAMPLE.COM";
}; Defensive patterns
Strategy: validation
Validate before calling
// Kerberos service principal must be primary/instance@REALM (instance optional).
String servicePrincipal = /* from JAAS config or keytab */;
java.util.regex.Pattern KRBFMT =
java.util.regex.Pattern.compile("^[^/@]+(/[^/@]+)?@[^/@]+$");
if (servicePrincipal == null || !KRBFMT.matcher(servicePrincipal).matches()) {
throw new IllegalArgumentException("Bad Kerberos principal format: " + servicePrincipal);
}
// only reached when sun.security.jgss.native=true; format is enforced by KerberosName.parse Type guard
// Narrow to a validated principal value object before handing to SASL setup.
static Optional<String> validKerberosPrincipal(String p) {
if (p == null) return Optional.empty();
java.util.regex.Pattern KRBFMT =
java.util.regex.Pattern.compile("^[^/@]+(/[^/@]+)?@[^/@]+$");
return KRBFMT.matcher(p).matches() ? Optional.of(p) : Optional.empty();
} Try / catch
try {
channelBuilder.configure(configs); // native GSS path parses the principal
} catch (KafkaException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Principal has name with unexpected format")) {
log.error("Kerberos principal in JAAS config is malformed", e);
failStartup(e);
}
throw e;
} Prevention
- This path is only hit when sun.security.jgss.native=true; confirm you actually need native JGSS before enabling it.
- Keep the Kerberos principal in JAAS config in standard form primary/instance@REALM (e.g. kafka/_HOST@EXAMPLE.COM).
- Resolve _HOST placeholders against the actual hostname; a stale host mapping produces a malformed principal.
- Verify the keytab principal with `klist -k` before deploying the JAAS config.
When it happens
Trigger: Broker configured for SASL/GSSAPI with -Dsun.security.jgss.native=true, where the JAAS principal entry (KafkaServer { ... principal="..." }) is not a valid KerberosName (missing '@REALM', contains illegal characters, or is a raw alias). KerberosName.parse throws IllegalArgumentException and SaslChannelBuilder wraps it.
Common situations: Setting the JAAS principal to a bare service alias like "kafka" instead of "kafka/_HOST@REALM"; copy-pasting a JAAS config that lost the realm; enabling native JGSS for the first time on a previously-java-only GSS setup where the principal string was lax.
Related errors
- `contextType` must be non-null if `securityProtocol` is `${s
- When the security.protocol configuration enables SASL, mecha
- The response is unrelated to Sasl request since its correlat
- Failed to create new KafkaAdminClient
- Not authorized to access topics: ${unauthorizedTopics}
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/5adc12e0395f704b.json.
Report an issue: GitHub.