apache/kafka · error · InvalidConfigurationException

Type ${principalBuilderClass.getName()} is not an instance o

Error message

Type ${principalBuilderClass.getName()} is not an instance of ${KafkaPrincipalBuilder.class.getName()}

What it means

Thrown by `ChannelBuilders.createPrincipalBuilder` when the configured `principal.builder.class` is neither null/DefaultKafkaPrincipalBuilder nor assignable to `KafkaPrincipalBuilder`. The broker uses this builder to convert the authenticated peer (SSL DN, SASL name, Kerberos principal) into a `KafkaPrincipal` for authorization; a class that doesn't implement the interface cannot be invoked. Unlike the other entries here, this is an `InvalidConfigurationException` (not IllegalArgumentException), reflecting that it stems from a bad user-supplied config value.

Source

Thrown at clients/src/main/java/org/apache/kafka/common/network/ChannelBuilders.java:229

    }

    private static void requireNonNullMode(ConnectionMode connectionMode, SecurityProtocol securityProtocol) {
        if (connectionMode == null)
            throw new IllegalArgumentException("`mode` must be non-null if `securityProtocol` is `" + securityProtocol + "`");
    }

    public static KafkaPrincipalBuilder createPrincipalBuilder(Map<String, ?> configs,
                                                               KerberosShortNamer kerberosShortNamer,
                                                               SslPrincipalMapper sslPrincipalMapper) {
        Class<?> principalBuilderClass = (Class<?>) configs.get(BrokerSecurityConfigs.PRINCIPAL_BUILDER_CLASS_CONFIG);
        final KafkaPrincipalBuilder builder;

        if (principalBuilderClass == null || principalBuilderClass == DefaultKafkaPrincipalBuilder.class) {
            builder = new DefaultKafkaPrincipalBuilder(kerberosShortNamer, sslPrincipalMapper);
        } else if (KafkaPrincipalBuilder.class.isAssignableFrom(principalBuilderClass)) {
            builder = (KafkaPrincipalBuilder) Utils.newInstance(principalBuilderClass);
        } else {
            throw new InvalidConfigurationException("Type " + principalBuilderClass.getName() + " is not " +
                    "an instance of " + KafkaPrincipalBuilder.class.getName());
        }

        if (builder instanceof Configurable)
            ((Configurable) builder).configure(configs);

        return builder;
    }

}

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Make your custom class `implements KafkaPrincipalBuilder` (override `build` and `configure`).
  2. If migrating from the old SSL PrincipalBuilder, wrap or rewrite it as a KafkaPrincipalBuilder (the old interface is removed).
  3. Remove the `principal.builder.class` config to fall back to `DefaultKafkaPrincipalBuilder`.
  4. Verify the JAR containing your custom builder is on the broker/client classpath and not shadowed by an older copy.

Example fix

// before
class MyPrincipalBuilder implements PrincipalBuilder { /* old SSL-only API */ }
props.put("principal.builder.class", "com.example.MyPrincipalBuilder");

// after
import org.apache.kafka.common.security.auth.KafkaPrincipalBuilder;

class MyPrincipalBuilder implements KafkaPrincipalBuilder {
    @Override public KafkaPrincipal build(AuthenticationContext<?> ctx) { /* ... */ }
    @Override public void configure(Map<String, ?> configs) { /* ... */ }
}
Defensive patterns

Strategy: type-guard

Validate before calling

Class<?> clazz = (Class<?>) configs.get(
    BrokerSecurityConfigs.PRINCIPAL_BUILDER_CLASS_CONFIG);
if (clazz != null && !KafkaPrincipalBuilder.class.isAssignableFrom(clazz)) {
    throw new org.apache.kafka.common.errors.InvalidConfigurationException(
        clazz.getName() + " is not a " + KafkaPrincipalBuilder.class.getName());
}
ChannelBuilders.createPrincipalBuilder(configs, kerberosShortNamer, sslPrincipalMapper);

Type guard

static boolean isPrincipalBuilder(Class<?> c) {
    return c != null && KafkaPrincipalBuilder.class.isAssignableFrom(c);
}

Try / catch

try {
    ChannelBuilders.createPrincipalBuilder(configs, kerberosShortNamer, sslPrincipalMapper);
} catch (org.apache.kafka.common.errors.InvalidConfigurationException e) {
    // "Type X is not an instance of org.apache.kafka.common.security.auth.KafkaPrincipalBuilder"
    // remove the offending class and fall back to DefaultKafkaPrincipalBuilder
    configs.remove(BrokerSecurityConfigs.PRINCIPAL_BUILDER_CLASS_CONFIG);
}

Prevention

When it happens

Trigger: Configuring `principal.builder.class` to a fully-qualified class name whose Class is not a subtype of `KafkaPrincipalBuilder`, then starting a broker or constructing a channel that calls `createPrincipalBuilder`. Hit when the class is an old `PrincipalBuilder` (the pre-0.10.2.0 SSL-only interface), a plain `Login` class, or an arbitrary bean.

Common situations: Upgrading from an old Kafka version where `org.apache.kafka.common.security.auth.PrincipalBuilder` (deprecated, SSL-only) was configured; the new API requires `KafkaPrincipalBuilder`. Copying a custom class name from another project without adding the dependency. Typing a class that exists but implements the wrong interface. Classpath shadowing where a stale older version of the class is loaded.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/cc7efcdc2648e663.json. Report an issue: GitHub.