{"id":"a28bbc7ec545aff8","repo":"apache/kafka","slug":"the-record-cannot-be-acknowledged-a28bbc","errorCode":null,"errorMessage":"The record cannot be acknowledged.","messagePattern":"The record cannot be acknowledged\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/clients/consumer/internals/ShareInFlightBatch.java","lineNumber":70,"sourceCode":"    }\n\n    public void addAcknowledgement(long offset, AcknowledgeType type) {\n        acknowledgements.add(offset, type);\n        if (type == AcknowledgeType.RENEW) {\n            checkForRenewAcknowledgements = true;\n        }\n    }\n\n    public void acknowledge(ConsumerRecord<K, V> record, AcknowledgeType type) {\n        if (inFlightRecords.get(record.offset()) != null) {\n            acknowledgements.add(record.offset(), type);\n            acknowledgedRecords.add(record.offset());\n            if (type == AcknowledgeType.RENEW) {\n                checkForRenewAcknowledgements = true;\n            }\n            return;\n        }\n        throw new IllegalStateException(\"The record cannot be acknowledged.\");\n    }\n\n    public void acknowledgeAll(AcknowledgeType type) {\n        for (Map.Entry<Long, ConsumerRecord<K, V>> entry : inFlightRecords.entrySet()) {\n            if (acknowledgements.addIfAbsent(entry.getKey(), type)) {\n                acknowledgedRecords.add(entry.getKey());\n            }\n        }\n        if (type == AcknowledgeType.RENEW) {\n            checkForRenewAcknowledgements = true;\n        }\n    }\n\n    public boolean checkAllInFlightAreAcknowledged() {\n        return inFlightRecords.size() == acknowledgedRecords.size();\n    }\n\n    public void addRecord(ConsumerRecord<K, V> record) {","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/clients/consumer/internals/ShareInFlightBatch.java#L52-L88","documentation":"Thrown by ShareInFlightBatch.acknowledge when the record's offset is not present in inFlightRecords. The in-flight batch is a TreeMap keyed by offset; acknowledging an offset that was never added (via addRecord) or that has already been drained by a prior commit/clear is a programming error and raises this IllegalStateException. It is the lowest-level guard beneath ShareFetch.acknowledge.","triggerScenarios":"Calling acknowledge(record) twice for the same record after the second call has the record removed; acknowledging a record whose offset was added as a gap (addGap) rather than a record; acknowledging an offset that belongs to a different batch than the one being mutated; acknowledging after commitAcknowledgements has reset the batch.","commonSituations":"Duplicate processing pipelines acknowledging the same offset; test code constructing synthetic ConsumerRecords; race between an async acknowledgement thread and the main poll loop that replaces the batch; acquisition-lock expiry having moved records out of in-flight state.","solutions":["Track which offsets you have already acknowledged (dedupe set) and skip duplicates.","Only acknowledge offsets returned by the most recent poll() against the current in-flight batch.","Avoid concurrent acknowledge calls from multiple threads; serialize acknowledgements with poll().","Increase share.group.acquire.timeout.ms if records are leaving the in-flight set before processing completes."],"exampleFix":"// before\nrecords.forEach(r -> {\n    exec.submit(() -> consumer.acknowledge(r, AcknowledgeType.ACCEPT));\n});\n\n// after\nrecords.forEach(r -> {\n    process(r);\n    consumer.acknowledge(r, AcknowledgeType.ACCEPT);\n});\nconsumer.commitAcknowledgements();","handlingStrategy":"validation","validationCode":"// Track acknowledged offsets per (topic, partition) so we never call acknowledge()\n// twice for the same offset, and never call it after the in-flight window has moved on.\nprivate final Map<String, Set<Long>> acked = new ConcurrentHashMap<>();\n\nvoid safeAcknowledge(ConsumerRecord<K,V> r, AcknowledgeType type) {\n    Set<Long> s = acked.computeIfAbsent(r.topic() + \":\" + r.partition(), k -> ConcurrentHashMap.newKeySet());\n    if (s.add(r.offset())) {            // false => already acknowledged\n        consumer.acknowledge(r, type);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    consumer.acknowledge(record, type);\n} catch (IllegalStateException e) {\n    // record.offset() is not in inFlightRecords: it was already acknowledged,\n    // or the in-flight batch has expired/released. Idempotent no-op.\n    log.debug(\"Record {}-{}@{} not in-flight; skipping acknowledge\",\n            record.topic(), record.partition(), record.offset(), e);\n}","preventionTips":["Maintain an acknowledged-offset set per partition to deduplicate ack calls.","Do not acknowledge records whose acquisition lock has expired; let the broker re-issue them.","Issue acks synchronously inside the poll loop; do not queue them onto background workers.","Call acknowledgeAll() once per batch when you can, instead of per-record acknowledge()."],"tags":["share-consumer","acknowledgement","api-misuse","kafka-client"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}