{"id":"9f2ab2b7b109ba44","repo":"apache/kafka","slug":"invalid-position-in-read-from","errorCode":null,"errorMessage":"Invalid position: {} in read from {}","messagePattern":"Invalid position: (.+?) in read from (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/record/internal/FileRecords.java","lineNumber":171,"sourceCode":"     *\n     * This method is reserved for cases where offset alignment is not necessary, such as in the replication of raft\n     * snapshots.\n     *\n     * @param position The start position to begin the read from\n     * @param size The number of bytes after the start position to include\n     * @return A unaligned slice of records on this message set limited based on the given position and size\n     */\n    public UnalignedFileRecords sliceUnaligned(int position, int size) {\n        int availableBytes = availableBytes(position, size);\n        return new UnalignedFileRecords(channel, this.start + position, availableBytes);\n    }\n\n    private int availableBytes(int position, int size) {\n        // Cache current size in case concurrent write changes it\n        int currentSizeInBytes = sizeInBytes();\n\n        if (position < 0)\n            throw new IllegalArgumentException(\"Invalid position: \" + position + \" in read from \" + this);\n        // position should always be relative to the start of the file hence compare with file size\n        // to verify if the position is within the file.\n        if (position > currentSizeInBytes)\n            throw new IllegalArgumentException(\"Slice from position \" + position + \" exceeds end position of \" + this);\n        if (size < 0)\n            throw new IllegalArgumentException(\"Invalid size: \" + size + \" in read from \" + this);\n\n        int end = this.start + position + size;\n        // Handle integer overflow or if end is beyond the end of the file\n        if (end < 0 || end > start + currentSizeInBytes)\n            end = this.start + currentSizeInBytes;\n        return end - (this.start + position);\n    }\n\n    /**\n     * Append a set of records to the file. This method is not thread-safe and must be\n     * protected with a lock.\n     *","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/record/internal/FileRecords.java#L153-L189","documentation":"Thrown by FileRecords.availableBytes when the requested position argument is negative. availableBytes computes the readable window for slice() and sliceUnaligned(); a negative start position is meaningless because byte offsets into the segment are always non-negative. This is a programmer-error guard, not an I/O condition.","triggerScenarios":"Calling FileRecords.slice(position, size) or sliceUnaligned(position, size) with position < 0. These are invoked during fetch response assembly, replication reads, and raft snapshot transfer when the caller computes a byte offset into a log segment.","commonSituations":"An upstream arithmetic underflow (e.g. subtracting a larger offset from a smaller one), an off-by-one in a custom consumer/replica path, or passing a relative position where an absolute one was expected. Rare in stock Kafka; usually surfaces from custom tooling or buggy Log/UnifiedLog refactor changes.","solutions":["Inspect the caller of slice/sliceUnaligned to confirm the position is computed from non-negative offsets (e.g. searchForOffsetFromFilePosition output).","Add a precondition or assertion earlier in the call chain so the negative value is caught with more context than availableBytes provides.","If you see this in production logs, grep the stack trace for the fetch/replication entry point and validate the startingOffset / startingPosition arguments."],"exampleFix":"// before: position may go negative on underflow\nint pos = targetOffset - baseOffset;\nFileRecords slice = records.slice(pos, size);\n\n// after: clamp/guard against negative positions explicitly\nif (pos < 0) throw new IllegalStateException(\"slice position negative for target=\" + targetOffset);\nFileRecords slice = records.slice(pos, size);","handlingStrategy":"validation","validationCode":"if (position < 0) {\n    throw new IllegalArgumentException(\n        \"read/slice position must be >= 0, got \" + position);\n}\nFileRecords slice = records.slice(position, size);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat all file positions as unsigned-by-contract; reject negatives at the boundary.","Derive position values only from searchForOffsetFromPosition results or batch.position(), not arithmetic on raw offsets.","Never reuse a position read from an untrusted source without clamping to >= 0."],"tags":["file-records","slice","validation","argument-error"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}