apache/kafka · error · KafkaException
Failed to make progress reading messages at {}={}. Received
Error message
Failed to make progress reading messages at {}={}. Received a non-empty fetch response from the server, but no complete records were found. What it means
KafkaException raised in FetchCollector.handleInitializeSuccess when the fetch response carries a non-empty records payload (bytes > 0) but iterating the record batches yields zero batches. Per KIP-74 this is impossible for brokers that support FetchRequest/Response v4+, so it indicates a malformed response, a broker bug, or an intermediary (proxy/serde) that corrupted the bytes. The client refuses to silently lose data, so it throws rather than advance the offset.
Source
Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/internals/FetchCollector.java:272
final long fetchOffset = completedFetch.nextFetchOffset();
// we are interested in this fetch only if the beginning offset matches the
// current consumed position
SubscriptionState.FetchPosition position = subscriptions.positionOrNull(tp);
if (position == null || position.offset != fetchOffset) {
log.debug("Discarding stale fetch response for partition {} since its offset {} does not match " +
"the expected offset {} or the partition has been unassigned", tp, fetchOffset, position);
return null;
}
final FetchResponseData.PartitionData partition = completedFetch.partitionData;
log.trace("Preparing to read {} bytes of data for partition {} with offset {}",
FetchResponse.recordsSize(partition), tp, position);
Iterator<? extends RecordBatch> batches = FetchResponse.recordsOrFail(partition).batches().iterator();
if (!batches.hasNext() && FetchResponse.recordsSize(partition) > 0) {
// This should not happen with brokers that support FetchRequest/Response V4 or higher (i.e. KIP-74)
throw new KafkaException("Failed to make progress reading messages at " + tp + "=" +
fetchOffset + ". Received a non-empty fetch response from the server, but no " +
"complete records were found.");
}
if (!updatePartitionState(partition, tp)) {
return null;
}
completedFetch.setInitialized();
return completedFetch;
}
private boolean updatePartitionState(final FetchResponseData.PartitionData partitionData,
final TopicPartition tp) {
if (partitionData.highWatermark() >= 0) {
log.trace("Updating high watermark for partition {} to {}", tp, partitionData.highWatermark());
if (!subscriptions.tryUpdatingHighWatermark(tp, partitionData.highWatermark())) {
return false;View on GitHub (pinned to c31c9215e1)
Solutions
- Ensure all brokers are at version 0.10.0 or higher (FetchResponse v4+); decommission legacy brokers.
- Remove or fix any HTTP/TCP proxy, sidecar, or capture tool between the client and brokers that may alter the response body.
- Upgrade kafka-clients to the latest release to benefit from stricter response validation and fixes.
- Capture a network trace (or enable TRACE logging of org.apache.kafka.clients.FetchCollector) to confirm the response bytes are intact end-to-end.
Example fix
// before: client points at mixed cluster with one 0.9 broker bootstrap.servers=broker-v9:9092,broker-v3:9092 // after: all brokers >= 0.10 and client aligned to cluster version bootstrap.servers=broker-v3:9092,broker-v3b:9092 # (decommission the 0.9 node)
Defensive patterns
Strategy: retry
Validate before calling
// This is a broker-version compatibility issue (KIP-74): the server returned bytes
// but no complete RecordBatch. You cannot validate it client-side. Ensure broker and
// client versions are aligned to avoid triggering it:
Properties p = new Properties();
p.put(ProducerConfig.BROKER_VERSION_COMPATIBILITY_ENABLE, "true"); // producer side
// On the consumer side, verify the broker reports a FetchRequest V4+ capable version:
Node node = consumer.partitionsFor("myTopic").get(0).leader();
// If node is null or the cluster is mid-upgrade, defer heavy consumption until stable. Try / catch
int attempts = 0;
while (attempts++ < 3) {
try {
return consumer.poll(Duration.ofMillis(500));
} catch (org.apache.kafka.common.KafkaException e) {
if (e.getMessage() != null && e.getMessage().startsWith("Failed to make progress reading messages")) {
// FetchCollector.java:272: non-empty response, zero complete batches.
// Almost always a broker < FetchRequest V4 or a mid-upgrade/transient corruption.
log.warn("Broker returned unparseable records for partition; retrying after metadata refresh (attempt {})", attempts);
consumer.requestOffsetReset(consumer.assignment()); // optional: force re-fetch from a clean offset
continue;
}
throw e;
}
}
throw new IllegalStateException("Could not make fetch progress after retries"); Prevention
- Keep broker and client versions aligned; the condition that raises this is essentially impossible with brokers supporting FetchRequest V4+.
- During a rolling upgrade, expect transient occurrences — retry with bounded backoff rather than aborting.
- Do not catch this as a generic Exception; isolate the 'Failed to make progress reading messages' message and retry, surface anything else.
- If it persists on a stable cluster, suspect on-disk corruption or an incompatible interceptor/serializer — capture the partition/offset from the message.
When it happens
Trigger: Triggered at FetchCollector.java:272 when FetchResponse.recordsSize(partition) > 0 but FetchResponse.recordsOrFail(partition).batches().iterator() has no next element.
Common situations: Talking to a down-level or buggy broker (< 0.10.0 / FetchResponse v3 or earlier); a misbehaving L7 proxy or sidecar that rewrites the fetch response; on-the-wire corruption from a faulty NIC / TLS terminator; broker version mismatch in a heterogeneous cluster; old broker mixed with new client during an upgrade.
Related errors
- Buffer underflow while parsing consumer protocol's header
- Malformed consumer protocol subscription
- Malformed consumer protocol assignment
- Unsupported subscription version: {}
- Unsupported assignment version: {}
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/967f7bcc28fe69ae.json.
Report an issue: GitHub.