You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jira@kafka.apache.org by "ChenXi (Jira)" <ji...@apache.org> on 2026/09/20 06:43:00 UTC

[jira] [Created] (KAFKA-21129) KRaft controller failover caused by an off-by-one in non-atomic batch appending

ChenXi created KAFKA-21129:
------------------------------

             Summary: KRaft controller failover caused by an off-by-one in non-atomic batch appending
                 Key: KAFKA-21129
                 URL: https://issues.apache.org/jira/browse/KAFKA-21129
             Project: Kafka
          Issue Type: Bug
          Components: controller
    Affects Versions: 4.3.1
            Reporter: ChenXi


QuorumController.appendRecords  (metadata/src/main/java/org/apache/kafka/controller/QuorumController.java:918-933) splits a non-atomic result into batches, but its
boundary check is off by one. When records.size() is an exact multiple of maxRecordsPerBatch, the final iteration calls the appender with an empty subList(size, size).
{code:java}
int startIndex = 0, numBatches = 0;
while (true) {
    numBatches++;
    int endIndex = startIndex + maxRecordsPerBatch;
    if (endIndex > records.size()) {
        long offset = appender.apply(records.subList(startIndex, records.size()));
        ...
        return offset;
    } else {
        appender.apply(records.subList(startIndex, endIndex));
    }
    startIndex += maxRecordsPerBatch;
}{code}
The production appender passes this empty list to RaftClient.prepareAppend, and KafkaRaftClient.append rejects empty batches with IllegalArgumentException
("Append failed because there are no records").

Since appendRecords only converts ApiException, the exception escapes the event handler and is treated as an unexpected fault, so the active controller renounces leadership and the client receives UnknownServerException.

The preceding full batches may already have been appended, so the change can take effect even though the client sees a failure.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)