apache/kafka · error · IllegalStateException
Implicit acknowledgement of delivery is being used.
Error message
Implicit acknowledgement of delivery is being used.
What it means
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.
Source
Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/internals/ShareConsumerImpl.java:1235
// We cannot leave unacknowledged records in EXPLICIT acknowledgement mode, so we throw an exception to the application.
throw new IllegalStateException("All records must be acknowledged in explicit acknowledgement mode.");
}
}
}
/**
* Returns any ready acknowledgements to be sent to the cluster.
*/
private Map<TopicIdPartition, NodeAcknowledgements> acknowledgementsToSend() {
return currentFetch.takeAcknowledgedRecords();
}
/**
* Called to verify if the acknowledgement mode is EXPLICIT, else throws an exception.
*/
private void ensureExplicitAcknowledgement() {
if (acknowledgementMode == ShareAcknowledgementMode.IMPLICIT) {
throw new IllegalStateException("Implicit acknowledgement of delivery is being used.");
}
}
/**
* Initializes the acknowledgement mode based on the configuration.
*/
private static ShareAcknowledgementMode initializeAcknowledgementMode(ConsumerConfig config) {
String s = config.getString(ConsumerConfig.SHARE_ACKNOWLEDGEMENT_MODE_CONFIG);
return ShareAcknowledgementMode.fromString(s);
}
/**
* Process acknowledgement events, if any, that were produced by the {@link ConsumerNetworkThread network thread}.
*/
void processAcknowledgementEvents() {
List<ShareAcknowledgementEvent> events = acknowledgementEventHandler.drainEvents();
if (!events.isEmpty()) {
for (ShareAcknowledgementEvent event : events) {View on GitHub (pinned to c31c9215e1)
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.
Example fix
// before
// props has no share.acknowledgement.mode -> defaults to IMPLICIT
for (ConsumerRecord<String,String> r : records) {
process(r);
consumer.acknowledge(r); // throws IllegalStateException
}
// after (option A - explicit)
props.put(ConsumerConfig.SHARE_ACKNOWLEDGEMENT_MODE_CONFIG, "explicit");
for (ConsumerRecord<String,String> r : records) {
process(r);
consumer.acknowledge(r);
}
// after (option B - implicit)
// leave mode as implicit and remove the acknowledge() calls
for (ConsumerRecord<String,String> r : records) {
process(r);
} Defensive patterns
Strategy: validation
Validate before calling
// Do not call acknowledge(...) when the consumer is configured for IMPLICIT mode.
String mode = props.getProperty(org.apache.kafka.clients.consumer.ConsumerConfig.SHARE_ACKNOWLEDGEMENT_MODE_CONFIG);
boolean isExplicit = "explicit".equalsIgnoreCase(mode);
if (isExplicit) {
consumer.acknowledge(record, org.apache.kafka.clients.consumer.AcknowledgeType.ACCEPT);
} else {
// Implicit mode: acknowledgement is automatic on the next poll; nothing to do.
log.debug("Skipping explicit acknowledge; consumer is in IMPLICIT mode");
} Type guard
null
Try / catch
try {
consumer.acknowledge(record, org.apache.kafka.clients.consumer.AcknowledgeType.ACCEPT);
} catch (IllegalStateException e) {
if (e.getMessage() != null && e.getMessage().contains("Implicit acknowledgement")) {
// Configuration mismatch: either switch the consumer to EXPLICIT mode, or stop calling acknowledge.
log.warn("acknowledge() ignored; consumer is running in IMPLICIT mode", e);
} else {
throw e;
}
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- Acknowledgement mode is null
- Invalid acknowledgement mode: {}
- Invalid value `{}` for configuration {}. The value must eith
- ShareAcquireMode is null
- Telemetry is not enabled. Set config `${ConsumerConfig.ENABL
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/4df3ade35293602f.json.
Report an issue: GitHub.