{"id":"1dd0b72df100a5c6","repo":"apache/kafka","slug":"when-the-security-protocol-configuration-enables-s","errorCode":null,"errorMessage":"When the security.protocol configuration enables SASL, mechanism must be non-null and non-empty string.","messagePattern":"When the security\\.protocol configuration enables SASL, mechanism must be non-null and non-empty string\\.","errorType":"validation","errorClass":"ConfigException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/CommonClientConfigs.java","lineNumber":322,"sourceCode":"                RETRY_BACKOFF_MAX_MS_CONFIG, retryBackoffMaxMs, retryBackoffMaxMs);\n        }\n\n        long connectionSetupTimeoutMs = config.getLong(SOCKET_CONNECTION_SETUP_TIMEOUT_MS_CONFIG);\n        long connectionSetupTimeoutMaxMs = config.getLong(SOCKET_CONNECTION_SETUP_TIMEOUT_MAX_MS_CONFIG);\n        if (connectionSetupTimeoutMs > connectionSetupTimeoutMaxMs) {\n            log.warn(\"Configuration '{}' with value '{}' is greater than configuration '{}' with value '{}'. \" +\n                    \"A static connection setup timeout with value '{}' will be applied.\",\n                SOCKET_CONNECTION_SETUP_TIMEOUT_MS_CONFIG, connectionSetupTimeoutMs,\n                SOCKET_CONNECTION_SETUP_TIMEOUT_MAX_MS_CONFIG, connectionSetupTimeoutMaxMs, connectionSetupTimeoutMaxMs);\n        }\n    }\n\n    public static void postValidateSaslMechanismConfig(AbstractConfig config) {\n        SecurityProtocol securityProtocol = SecurityProtocol.forName(config.getString(CommonClientConfigs.SECURITY_PROTOCOL_CONFIG));\n        String clientSaslMechanism = config.getString(SaslConfigs.SASL_MECHANISM);\n        if (securityProtocol == SecurityProtocol.SASL_PLAINTEXT || securityProtocol == SecurityProtocol.SASL_SSL) {\n            if (clientSaslMechanism == null || clientSaslMechanism.isEmpty()) {\n                throw new ConfigException(SaslConfigs.SASL_MECHANISM, null, \"When the \" + CommonClientConfigs.SECURITY_PROTOCOL_CONFIG +\n                        \" configuration enables SASL, mechanism must be non-null and non-empty string.\");\n            }\n        }\n    }\n\n    public static List<MetricsReporter> metricsReporters(AbstractConfig config) {\n        return metricsReporters(Collections.emptyMap(), config);\n    }\n\n    public static List<MetricsReporter> metricsReporters(String clientId, AbstractConfig config) {\n        return metricsReporters(Collections.singletonMap(CommonClientConfigs.CLIENT_ID_CONFIG, clientId), config);\n    }\n\n    public static List<MetricsReporter> metricsReporters(Map<String, Object> clientIdOverride, AbstractConfig config) {\n        return config.getConfiguredInstances(CommonClientConfigs.METRIC_REPORTER_CLASSES_CONFIG,\n                MetricsReporter.class, clientIdOverride);\n    }\n","sourceCodeStart":304,"sourceCodeEnd":340,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/CommonClientConfigs.java#L304-L340","documentation":"ConfigException thrown by CommonClientConfigs.postValidateSaslMechanismConfig when security.protocol is SASL_PLAINTEXT or SASL_SSL but sasl.mechanism is null or empty. The validation runs after config parsing and guarantees a SASL client cannot be constructed without a concrete mechanism to negotiate.","triggerScenarios":"Setting 'security.protocol=SASL_SSL' (or SASL_PLAINTEXT) without setting 'sasl.mechanism', or setting it to an empty string. Triggered by any client constructor that runs postConfigureSasl on its AbstractConfig.","commonSituations":"Switching a client from PLAINTEXT to SASL_SSL for the first time and forgetting the mechanism; loading mechanism from a property whose key is misspelled (e.g. 'sasl.mechanisms'); or env var unset.","solutions":["Set sasl.mechanism to a supported value: PLAIN, SCRAM-SHA-256, SCRAM-SHA-512, GSSAPI, OAUTHBEARER, etc.","Confirm the property key is exactly 'sasl.mechanism' (singular) and not blank.","If using a jaas.config, ensure the login module matches the chosen mechanism."],"exampleFix":"// before\nprops.put(\"security.protocol\", \"SASL_SSL\");\n// sasl.mechanism missing -> ConfigException\n// after\nprops.put(\"security.protocol\", \"SASL_SSL\");\nprops.put(\"sasl.mechanism\", \"SCRAM-SHA-512\");","handlingStrategy":"validation","validationCode":"// If security.protocol is SASL_PLAINTEXT or SASL_SSL, the sasl.mechanism\n// must be set to a non-empty string. Validate the pair together:\nimport org.apache.kafka.common.security.auth.SecurityProtocol;\n\nstatic void validateSasl(Map<String, Object> props) {\n    String sp = (String) props.getOrDefault(\"security.protocol\", \"PLAINTEXT\");\n    SecurityProtocol proto = SecurityProtocol.forName(sp);\n    if (proto == SecurityProtocol.SASL_PLAINTEXT || proto == SecurityProtocol.SASL_SSL) {\n        String mech = (String) props.get(\"sasl.mechanism\");\n        if (mech == null || mech.isBlank())\n            throw new IllegalArgumentException(\n                \"sasl.mechanism must be set when security.protocol=\" + sp);\n    }\n}","typeGuard":"static boolean needsSaslMechanism(String securityProtocol) {\n    SecurityProtocol p = SecurityProtocol.forName(securityProtocol);\n    return p == SecurityProtocol.SASL_PLAINTEXT || p == SecurityProtocol.SASL_SSL;\n}\n\n// if (needsSaslMechanism(sp) && (mech == null || mech.isBlank())) fail();","tryCatchPattern":"try {\n    consumer = new KafkaConsumer<>(props);\n} catch (ConfigException e) {\n    if (e.getMessage().contains(\"mechanism must be non-null and non-empty\")) {\n        // Pair the security.protocol with the matching default mechanism,\n        // or fail the deploy and ask the operator to set sasl.mechanism.\n        throw new ConfigurationException(\"Set sasl.mechanism (e.g. SCRAM-SHA-512, PLAIN, GSSAPI)\", e);\n    }\n    throw e;\n}","preventionTips":["Treat security.protocol and sasl.mechanism as a paired setting — never set one without the other in the same config commit.","Use well-known mechanism names verbatim (PLAIN, SCRAM-SHA-256, SCRAM-SHA-512, GSSAPI, OAUTHBEARER); a typo is the same as missing.","Centralise security config so it cannot drift between producer and consumer instances of the same app.","Add a config self-test in CI that constructs (and immediately closes) a client with the production security settings."],"tags":["config","sasl","security","validation"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}