{"record":{"id":"6b8f01ec34a3ad93","repo":"apache/kafka","slug":"invalidconfigs-cannot-be-set-when-group-protocol","errorCode":null,"errorMessage":"{invalidConfigs} cannot be set when group.protocol={groupProtocol}","messagePattern":"(.+?) cannot be set when group\\.protocol=(.+?)","errorType":"validation","errorClass":"ConfigException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/ConsumerConfig.java","lineNumber":838,"sourceCode":"        String groupProtocol = getString(GROUP_PROTOCOL_CONFIG);\n        if (GroupProtocol.CLASSIC.name().equalsIgnoreCase(groupProtocol)) {\n            checkUnsupportedConfigsPostProcess(GroupProtocol.CLASSIC, CLASSIC_PROTOCOL_UNSUPPORTED_CONFIGS);\n        } else if (GroupProtocol.CONSUMER.name().equalsIgnoreCase(groupProtocol)) {\n            checkUnsupportedConfigsPostProcess(GroupProtocol.CONSUMER, CONSUMER_PROTOCOL_UNSUPPORTED_CONFIGS);\n        }\n    }\n\n    private void checkUnsupportedConfigsPostProcess(GroupProtocol groupProtocol, List<String> unsupportedConfigs) {\n        if (getString(GROUP_PROTOCOL_CONFIG).equalsIgnoreCase(groupProtocol.name())) {\n            List<String> invalidConfigs = new ArrayList<>();\n            unsupportedConfigs.forEach(configName -> {\n                Object config = originals().get(configName);\n                if (config != null && !Utils.isBlank(config.toString())) {\n                    invalidConfigs.add(configName);\n                }\n            });\n            if (!invalidConfigs.isEmpty()) {\n                throw new ConfigException(String.join(\", \", invalidConfigs) +\n                        \" cannot be set when \" + GROUP_PROTOCOL_CONFIG + \"=\" + groupProtocol.name());\n            }\n        }\n    }\n\n    /**\n     * Constructs a new ConsumerConfig with the given properties.\n     *\n     * @param props The consumer configuration properties\n     */\n    public ConsumerConfig(Properties props) {\n        super(CONFIG, props);\n    }\n\n    /**\n     * Constructs a new ConsumerConfig with the given properties.\n     *\n     * @param props The consumer configuration properties","sourceCodeStart":820,"sourceCodeEnd":856,"githubUrl":"https://github.com/apache/kafka/blob/996fb4585aa1bcc8980b0e1b8d6b168b986cd979/clients/src/main/java/org/apache/kafka/clients/consumer/ConsumerConfig.java#L820-L856","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nprops.put(\"group.protocol\", \"consumer\");\nprops.put(\"partition.assignment.strategy\", CooperativeStickyAssignor.class.getName());\nprops.put(\"heartbeat.interval.ms\", \"3000\");\nnew KafkaConsumer<>(props);\n\n// after\nprops.put(\"group.protocol\", \"consumer\");\n// partition.assignment.strategy, heartbeat.interval.ms, session.timeout.ms removed\nnew KafkaConsumer<>(props);","handlingStrategy":"validation","validationCode":"String protocol = String.valueOf(configs.get(ConsumerConfig.GROUP_PROTOCOL_CONFIG));\nList<String> forbidden = \"CONSUMER\".equalsIgnoreCase(protocol)\n    ? List.of(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG,\n              ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG,\n              ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG)\n    : List.of(\"group.remote.assignor\");\nList<String> present = forbidden.stream().filter(configs::containsKey).toList();\nif (!present.isEmpty()) {\n    throw new ConfigException(present + \" not allowed with group.protocol=\" + protocol);\n}","typeGuard":"static boolean groupProtocolConfigConsistent(Map<String,Object> c) {\n    String p = String.valueOf(c.get(ConsumerConfig.GROUP_PROTOCOL_CONFIG));\n    if (\"CONSUMER\".equalsIgnoreCase(p)) {\n        return !c.containsKey(ConsumerConfig.PARTITION_ASSIGNMENT_STRATEGY_CONFIG)\n            && !c.containsKey(ConsumerConfig.HEARTBEAT_INTERVAL_MS_CONFIG)\n            && !c.containsKey(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG);\n    }\n    return true;\n}","tryCatchPattern":"try {\n    consumer = new KafkaConsumer<>(props);\n} catch (ConfigException e) {\n    if (e.getMessage().contains(\"cannot be set when group.protocol\")) {\n        // strip the offending keys and retry, or surface to the user\n        throw e;\n    }\n    throw e;\n}","preventionTips":["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."],"tags":["consumer","config","group-protocol","validation"],"backgroundTag":null,"analyzedSha":"996fb4585aa1bcc8980b0e1b8d6b168b986cd979","analyzedAt":"2026-08-11T22:03:28.655Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}