{"id":"4df3ade35293602f","repo":"apache/kafka","slug":"implicit-acknowledgement-of-delivery-is-being-used","errorCode":null,"errorMessage":"Implicit acknowledgement of delivery is being used.","messagePattern":"Implicit acknowledgement of delivery is being used\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/ShareConsumerImpl.java","lineNumber":1235,"sourceCode":"                // We cannot leave unacknowledged records in EXPLICIT acknowledgement mode, so we throw an exception to the application.\n                throw new IllegalStateException(\"All records must be acknowledged in explicit acknowledgement mode.\");\n            }\n        }\n    }\n\n    /**\n     * Returns any ready acknowledgements to be sent to the cluster.\n     */\n    private Map<TopicIdPartition, NodeAcknowledgements> acknowledgementsToSend() {\n        return currentFetch.takeAcknowledgedRecords();\n    }\n\n    /**\n     * Called to verify if the acknowledgement mode is EXPLICIT, else throws an exception.\n     */\n    private void ensureExplicitAcknowledgement() {\n        if (acknowledgementMode == ShareAcknowledgementMode.IMPLICIT) {\n            throw new IllegalStateException(\"Implicit acknowledgement of delivery is being used.\");\n        }\n    }\n\n    /**\n     * Initializes the acknowledgement mode based on the configuration.\n     */\n    private static ShareAcknowledgementMode initializeAcknowledgementMode(ConsumerConfig config) {\n        String s = config.getString(ConsumerConfig.SHARE_ACKNOWLEDGEMENT_MODE_CONFIG);\n        return ShareAcknowledgementMode.fromString(s);\n    }\n\n    /**\n     * Process acknowledgement events, if any, that were produced by the {@link ConsumerNetworkThread network thread}.\n     */\n    void processAcknowledgementEvents() {\n        List<ShareAcknowledgementEvent> events = acknowledgementEventHandler.drainEvents();\n        if (!events.isEmpty()) {\n            for (ShareAcknowledgementEvent event : events) {","sourceCodeStart":1217,"sourceCodeEnd":1253,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/ShareConsumerImpl.java#L1217-L1253","documentation":"Thrown by ensureExplicitAcknowledgement() (line 1235) when acknowledge(...) is called while the consumer is in IMPLICIT acknowledgement mode. In implicit mode the client auto-acknowledges every record in the batch at poll time (line 1206-1207), so a manual acknowledge() call is contradictory and would double-ack. The guard rejects it so the application detects the mismatch between its acknowledgement calls and the configured mode.","triggerScenarios":"Calling consumer.acknowledge(record) or consumer.acknowledge(record, type) while share.acknowledgement.mode is implicit (the default). The same guard fires from both the single-record and the topic-partition-offset overloads (lines 805 and 818).","commonSituations":"Code ported from a classic KafkaConsumer.commitSync() pattern into a share consumer without realizing the default mode is implicit; upgrading the client and inheriting the new default; mixing two code paths — one written for explicit, one for implicit — against a consumer configured as implicit; documentation/example confusion between accept-on-poll and explicit ack.","solutions":["If you want per-record control, set share.acknowledgement.mode=explicit in the consumer config and remove any auto-ack assumptions.","If implicit semantics are what you want, delete the manual consumer.acknowledge(...) calls — the consumer acks the whole batch automatically at poll().","Make the mode explicit in config rather than relying on the default, so future code reads know which contract is in force.","Audit both acknowledge() call sites (record and topic/partition/offset overloads) since the guard covers both."],"exampleFix":"// before\n// props has no share.acknowledgement.mode -> defaults to IMPLICIT\nfor (ConsumerRecord<String,String> r : records) {\n    process(r);\n    consumer.acknowledge(r); // throws IllegalStateException\n}\n\n// after (option A - explicit)\nprops.put(ConsumerConfig.SHARE_ACKNOWLEDGEMENT_MODE_CONFIG, \"explicit\");\nfor (ConsumerRecord<String,String> r : records) {\n    process(r);\n    consumer.acknowledge(r);\n}\n\n// after (option B - implicit)\n// leave mode as implicit and remove the acknowledge() calls\nfor (ConsumerRecord<String,String> r : records) {\n    process(r);\n}","handlingStrategy":"validation","validationCode":"// Do not call acknowledge(...) when the consumer is configured for IMPLICIT mode.\nString mode = props.getProperty(org.apache.kafka.clients.consumer.ConsumerConfig.SHARE_ACKNOWLEDGEMENT_MODE_CONFIG);\nboolean isExplicit = \"explicit\".equalsIgnoreCase(mode);\nif (isExplicit) {\n    consumer.acknowledge(record, org.apache.kafka.clients.consumer.AcknowledgeType.ACCEPT);\n} else {\n    // Implicit mode: acknowledgement is automatic on the next poll; nothing to do.\n    log.debug(\"Skipping explicit acknowledge; consumer is in IMPLICIT mode\");\n}","typeGuard":"null","tryCatchPattern":"try {\n    consumer.acknowledge(record, org.apache.kafka.clients.consumer.AcknowledgeType.ACCEPT);\n} catch (IllegalStateException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Implicit acknowledgement\")) {\n        // Configuration mismatch: either switch the consumer to EXPLICIT mode, or stop calling acknowledge.\n        log.warn(\"acknowledge() ignored; consumer is running in IMPLICIT mode\", e);\n    } else {\n        throw e;\n    }\n}","preventionTips":["Confirm the share.acknowledgement.mode before writing any per-record acknowledge() calls.","Encapsulate acknowledgement behind a helper that no-ops when mode is IMPLICIT.","Treat a switch between implicit and explicit mode as a consumer recreation event, not a runtime call path."],"tags":["share-consumer","acknowledgement","implicit-mode","config"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}