apache/kafka · error · IllegalArgumentException

`clientSaslMechanism` must be non-null in client mode if `se

Error message

`clientSaslMechanism` must be non-null in client mode if `securityProtocol` is `${securityProtocol}`

What it means

Thrown by `ChannelBuilders.clientChannelBuilder` when the security protocol is SASL_PLAINTEXT or SASL_SSL but `clientSaslMechanism` is null. A SASL client must name exactly which mechanism it authenticates with (PLAIN, SCRAM-SHA-256, SCRAM-SHA-512, GSSAPI, OAUTHBEARER, DELEGATION_TOKEN, etc.) because that string drives JAAS context loading and mechanism negotiation. Null would NPE during `JaasContext.loadServerContext`/client context construction, so it is rejected up front.

Source

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

     * @param logContext the log context instance
     *
     * @return the configured `ChannelBuilder`
     * @throws IllegalArgumentException if `mode` invariants described above is not maintained
     */
    public static ChannelBuilder clientChannelBuilder(
            SecurityProtocol securityProtocol,
            JaasContext.Type contextType,
            AbstractConfig config,
            ListenerName listenerName,
            String clientSaslMechanism,
            Time time,
            LogContext logContext) {

        if (securityProtocol == SecurityProtocol.SASL_PLAINTEXT || securityProtocol == SecurityProtocol.SASL_SSL) {
            if (contextType == null)
                throw new IllegalArgumentException("`contextType` must be non-null if `securityProtocol` is `" + securityProtocol + "`");
            if (clientSaslMechanism == null)
                throw new IllegalArgumentException("`clientSaslMechanism` must be non-null in client mode if `securityProtocol` is `" + securityProtocol + "`");
        }
        return create(securityProtocol, ConnectionMode.CLIENT, contextType, config, listenerName, false, clientSaslMechanism,
            null, null, time, logContext, null);
    }

    /**
     * @param listenerName the listenerName
     * @param isInterBrokerListener whether or not this listener is used for inter-broker requests
     * @param securityProtocol the securityProtocol
     * @param config server config
     * @param credentialCache Credential cache for SASL/SCRAM if SCRAM is enabled
     * @param tokenCache Delegation token cache
     * @param time the time instance
     * @param logContext the log context instance
     * @param apiVersionSupplier supplier for ApiVersions responses sent prior to authentication
     *
     * @return the configured `ChannelBuilder`
     */

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Set `sasl.mechanism` in the client config (e.g. `props.put("sasl.mechanism", "SCRAM-SHA-512")`).
  2. If calling clientChannelBuilder directly, pass the resolved mechanism string explicitly.
  3. Verify the mechanism appears in the broker's `sasl.enabled.mechanisms` for server-side compatibility.

Example fix

// before
props.put("security.protocol", "SASL_SSL");
// sasl.mechanism missing

// after
props.put("security.protocol", "SASL_SSL");
props.put("sasl.mechanism", "SCRAM-SHA-512");
Defensive patterns

Strategy: validation

Validate before calling

boolean isSasl = securityProtocol == SecurityProtocol.SASL_PLAINTEXT
                    || securityProtocol == SecurityProtocol.SASL_SSL;
if (isSasl && (clientSaslMechanism == null || clientSaslMechanism.isEmpty())) {
    throw new IllegalArgumentException(
        "clientSaslMechanism required for client-mode " + securityProtocol);
}
ChannelBuilders.clientChannelBuilder(
    securityProtocol, contextType, config, listenerName, clientSaslMechanism, time, logContext);

Try / catch

try {
    ChannelBuilders.clientChannelBuilder(
        securityProtocol, contextType, config, listenerName,
        clientSaslMechanism, time, logContext);
} catch (IllegalArgumentException e) {
    // "`clientSaslMechanism` must be non-null in client mode if `securityProtocol` is SASL_*"
    clientSaslMechanism = "PLAIN"; // or read from config: sasl.mechanism
}

Prevention

When it happens

Trigger: Calling `ChannelBuilders.clientChannelBuilder(SASL_*, contextType, config, listenerName, null, time, logContext)`. In standard clients this surfaces when `sasl.mechanism` config is unset/blank and the bootstrap fails to resolve it to a non-null string.

Common situations: Forgetting to set `sasl.mechanism` in client properties (common when adding SASL_SSL to an existing PLAINTEXT client). Setting it under a listener-prefixed key that the client doesn't read. Typos like `sasl.mechanisms` (plural). Custom client wrappers that pass null instead of reading the config.

Related errors


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