{"id":"90d255a9975fc808","repo":"apache/kafka","slug":"failed-to-load-record-batch-at-position-from","errorCode":null,"errorMessage":"Failed to load record batch at position {} from {}","messagePattern":"Failed to load record batch at position (.+?) from (.+?)","errorType":"exception","errorClass":"KafkaException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/record/internal/FileLogInputStream.java","lineNumber":220,"sourceCode":"        protected RecordBatch loadBatchHeader() {\n            if (fullBatch != null)\n                return fullBatch;\n\n            if (batchHeader == null)\n                batchHeader = loadBatchWithSize(headerSize(), \"record batch header\");\n\n            return batchHeader;\n        }\n\n        private RecordBatch loadBatchWithSize(int size, String description) {\n            FileChannel channel = fileRecords.channel();\n            try {\n                ByteBuffer buffer = ByteBuffer.allocate(size);\n                Utils.readFullyOrFail(channel, buffer, position, description);\n                buffer.rewind();\n                return toMemoryRecordBatch(buffer);\n            } catch (IOException e) {\n                throw new KafkaException(\"Failed to load record batch at position \" + position + \" from \" + fileRecords, e);\n            }\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o)\n                return true;\n            if (o == null || getClass() != o.getClass())\n                return false;\n\n            FileChannelRecordBatch that = (FileChannelRecordBatch) o;\n\n            FileChannel channel = fileRecords == null ? null : fileRecords.channel();\n            FileChannel thatChannel = that.fileRecords == null ? null : that.fileRecords.channel();\n\n            return offset == that.offset &&\n                    position == that.position &&\n                    batchSize == that.batchSize &&","sourceCodeStart":202,"sourceCodeEnd":238,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/record/internal/FileLogInputStream.java#L202-L238","documentation":"Thrown by FileChannelRecordBatch.loadBatchWithSize() when Utils.readFullyOrFail() fails with IOException while loading a batch (or its header) fully into a heap ByteBuffer for in-memory access. This is the path behind loadFullBatch() / loadBatchHeader(), used by iterator(), streamingIterator(), isValid(), ensureValid(), and the accessor methods (compressionType, timestampType, etc.). Unlike writeTo (error 528), this materializes the batch into memory; the IOException is wrapped as KafkaException.","triggerScenarios":"Calling any method on a FileChannelRecordBatch that triggers loadFullBatch() or loadBatchHeader() (iterator, streamingIterator, isValid, ensureValid, compressionType, timestampType, checksum, maxTimestamp) when Utils.readFullyOrFail(channel, buffer, position, description) throws IOException. readFullyOrFail additionally throws if fewer than the requested bytes could be read (short read), so a truncated segment tail also surfaces here.","commonSituations":"Segment file closed or deleted (retention, roll, broker shutdown) while a lazy batch reference is still being accessed; the recorded position+size extends past the actual file length due to truncation or a torn write; disk/FS I/O errors; or a stale batch reference retained across a log cleaning/compaction cycle on a compacted topic.","solutions":["Confirm the segment still exists and is open at access time; avoid retaining FileChannelRecordBatch references across operations that may roll/delete segments (retention, compaction).","Run kafka-dump-log.sh on the segment to verify the batch at the recorded position is fully readable and not in a truncated tail.","If the file was truncated, fix the recovery-point / last-stable-offset metadata so loaders do not attempt to read past the valid region.","Check disk/FS health (dmesg, SMART) for low-level I/O failures; recover from ISR if data is genuinely unreadable."],"exampleFix":"// before: lazy access after the segment may be gone\nFileChannelRecordBatch b = input.nextBatch();\n// ... broker rolls/deletes segment ...\nb.ensureValid(); // IOException -> KafkaException\n// after: force full materialization while the channel is live\nRecordBatch mem = b.loadFullBatch();  // or iterate immediately\n// then operate on `mem`, drop the file-backed reference","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  // Triggered lazily by iterator(), isValid(), ensureValid(), compressionType(), etc.\n  Iterator<Record> it = batch.iterator();\n} catch (org.apache.kafka.common.KafkaException e) {\n  // loadBatchWithSize() read failed via Utils.readFullyOrFail — IOException on the channel.\n  java.io.IOException cause = (java.io.IOException) e.getCause();\n  log.warn(\"Failed to load batch at position {} from {}: {}\", batch.position(), batch, cause.getMessage());\n}","preventionTips":["loadFullBatch / loadBatchHeader are lazy — any of iterator(), isValid(), ensureValid(), compressionType(), checksum() can trigger this; wrap all batch-access call sites, not just nextBatch().","Ensure the FileChannel is open and readable when these lazy accessors fire; opening a batch and then closing the channel before iterating is the common trigger.","On IOException cause, retry once after reopening FileRecords at the same position; persistent failure means segment damage.","For long-lived batch references, call loadFullBatch() eagerly while the channel is known-good to detach from the FileChannel.","Differentiate from 528: 529 is the lazy load path (readFullyOrFail, fails fast on short read); 528 is writeTo (readFully, tolerant). Recovery handling is the same."],"tags":["kafka","records","file-records","io-exception","lazy-load","broker"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}