apache/kafka · error · ConfigException
cannot be set when group.protocol=
Error message
{invalidConfigs} cannot be set when group.protocol={groupProtocol} What it means
Thrown by ConsumerConfig.checkUnsupportedConfigsPostProcess when one or more configs that are invalid for the selected group.protocol are present and non-blank. For the CONSUMER protocol, partition.assignment.strategy, heartbeat.interval.ms, session.timeout.ms and the share-mode configs are disallowed; for the CLASSIC protocol, group.remote.assignor and the share-mode configs are disallowed. The protocol-specific coordinator manages these internally.
Solutions
- Remove the offending keys listed in the error message from the consumer Properties.
- Switch group.protocol to the one matching the configs you need (e.g. classic if you require a custom partition assignor).
- Maintain a per-protocol config template and load only the relevant set.
Example fix
// before
props.put("group.protocol", "consumer");
props.put("partition.assignment.strategy", CooperativeStickyAssignor.class.getName());
props.put("heartbeat.interval.ms", "3000");
new KafkaConsumer<>(props);
// after
props.put("group.protocol", "consumer");
// partition.assignment.strategy, heartbeat.interval.ms, session.timeout.ms removed
new KafkaConsumer<>(props); Defensive patterns
Strategy: validation
Validate before calling
String protocol = String.valueOf(configs.get(ConsumerConfig.GROUP_PROTOCOL_CONFIG));
List<String> forbidden = "CONSUMER".equalsIgnoreCase(protocol)
? List.of(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,
ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG,
ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG)
: List.of("group.remote.assignor");
List<String> present = forbidden.stream().filter(configs::containsKey).toList();
if (!present.isEmpty()) {
throw new ConfigException(present + " not allowed with group.protocol=" + protocol);
} Type guard
static boolean groupProtocolConfigConsistent(Map<String,Object> c) {
String p = String.valueOf(c.get(ConsumerConfig.GROUP_PROTOCOL_CONFIG));
if ("CONSUMER".equalsIgnoreCase(p)) {
return !c.containsKey(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG)
&& !c.containsKey(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG)
&& !c.containsKey(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG);
}
return true;
} Try / catch
try {
consumer = new KafkaConsumer<>(props);
} catch (ConfigException e) {
if (e.getMessage().contains("cannot be set when group.protocol")) {
// strip the offending keys and retry, or surface to the user
throw e;
}
throw e;
} Prevention
- Maintain one config template per group.protocol value.
- Strip classic-only keys when migrating to the consumer protocol.
- Validate config consistency before constructing the consumer.
When it happens
Trigger: Setting group.protocol=consumer while also setting partition.assignment.strategy, heartbeat.interval.ms, or session.timeout.ms. Or setting group.protocol=classic while also setting group.remote.assignor. Any non-blank value (including 'null' string in some edge cases of user input) for these keys triggers the check.
Common situations: Migrating from classic to consumer protocol and forgetting to strip classic-only configs; copy-pasted consumer templates that always include assignor/heartbeat/session settings; tooling that injects these configs unconditionally.
Related errors
- enable.auto.commit cannot be set to true when default group…
- must be non-null.
- The configured group.id should not be an empty string or…
- cannot be set when using a share group.
- Failed to construct kafka consumer
AI-assisted analysis of apache/kafka@996fb4585a (2026-08-11).
Data as JSON: /api/errors/6b8f01ec34a3ad93.
Report an issue: GitHub.
Appendix: source
Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/ConsumerConfig.java:838
String groupProtocol = getString(GROUP_PROTOCOL_CONFIG);
if (GroupProtocol.CLASSIC.name().equalsIgnoreCase(groupProtocol)) {
checkUnsupportedConfigsPostProcess(GroupProtocol.CLASSIC, CLASSIC_PROTOCOL_UNSUPPORTED_CONFIGS);
} else if (GroupProtocol.CONSUMER.name().equalsIgnoreCase(groupProtocol)) {
checkUnsupportedConfigsPostProcess(GroupProtocol.CONSUMER, CONSUMER_PROTOCOL_UNSUPPORTED_CONFIGS);
}
}
private void checkUnsupportedConfigsPostProcess(GroupProtocol groupProtocol, List<String> unsupportedConfigs) {
if (getString(GROUP_PROTOCOL_CONFIG).equalsIgnoreCase(groupProtocol.name())) {
List<String> invalidConfigs = new ArrayList<>();
unsupportedConfigs.forEach(configName -> {
Object config = originals().get(configName);
if (config != null && !Utils.isBlank(config.toString())) {
invalidConfigs.add(configName);
}
});
if (!invalidConfigs.isEmpty()) {
throw new ConfigException(String.join(", ", invalidConfigs) +
" cannot be set when " + GROUP_PROTOCOL_CONFIG + "=" + groupProtocol.name());
}
}
}
/**
* Constructs a new ConsumerConfig with the given properties.
*
* @param props The consumer configuration properties
*/
public ConsumerConfig(Properties props) {
super(CONFIG, props);
}
/**
* Constructs a new ConsumerConfig with the given properties.
*
* @param props The consumer configuration propertiesView on GitHub (pinned to 996fb4585a)