From 7a881ff899b882a90a180c1e226629ed475ddc91 Mon Sep 17 00:00:00 2001 From: uros-b <221401595+uros-b@users.noreply.github.com> Date: Wed, 29 Jul 2026 22:34:10 +0000 Subject: [PATCH 1/2] Core: Include CRC values in DV deserialization error message --- .../org/apache/iceberg/deletes/BitmapPositionDeleteIndex.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/apache/iceberg/deletes/BitmapPositionDeleteIndex.java b/core/src/main/java/org/apache/iceberg/deletes/BitmapPositionDeleteIndex.java index 376b391d9c24..f499ebcf1c37 100644 --- a/core/src/main/java/org/apache/iceberg/deletes/BitmapPositionDeleteIndex.java +++ b/core/src/main/java/org/apache/iceberg/deletes/BitmapPositionDeleteIndex.java @@ -150,7 +150,8 @@ public static PositionDeleteIndex deserialize(byte[] bytes, DeleteFile deleteFil int crc = computeChecksum(bytes, bitmapDataLength); int crcOffset = LENGTH_SIZE_BYTES + bitmapDataLength; int expectedCrc = buffer.getInt(crcOffset); - Preconditions.checkArgument(crc == expectedCrc, "Invalid CRC"); + Preconditions.checkArgument( + crc == expectedCrc, "Invalid CRC: %s, expected %s", crc, expectedCrc); return new BitmapPositionDeleteIndex(bitmap, deleteFile); } From df5800c482b6e9f6d44363228647b06d0cdbf7aa Mon Sep 17 00:00:00 2001 From: uros-b <221401595+uros-b@users.noreply.github.com> Date: Fri, 31 Jul 2026 15:06:08 +0000 Subject: [PATCH 2/2] Address comments --- .../deletes/BitmapPositionDeleteIndex.java | 6 +++++- .../TestBitmapPositionDeleteIndex.java | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/apache/iceberg/deletes/BitmapPositionDeleteIndex.java b/core/src/main/java/org/apache/iceberg/deletes/BitmapPositionDeleteIndex.java index f499ebcf1c37..29cd368616b0 100644 --- a/core/src/main/java/org/apache/iceberg/deletes/BitmapPositionDeleteIndex.java +++ b/core/src/main/java/org/apache/iceberg/deletes/BitmapPositionDeleteIndex.java @@ -151,7 +151,11 @@ public static PositionDeleteIndex deserialize(byte[] bytes, DeleteFile deleteFil int crcOffset = LENGTH_SIZE_BYTES + bitmapDataLength; int expectedCrc = buffer.getInt(crcOffset); Preconditions.checkArgument( - crc == expectedCrc, "Invalid CRC: %s, expected %s", crc, expectedCrc); + crc == expectedCrc, + "Invalid CRC for deletion vector %s: 0x%s, expected 0x%s", + deleteFile.location(), + Integer.toHexString(crc), + Integer.toHexString(expectedCrc)); return new BitmapPositionDeleteIndex(bitmap, deleteFile); } diff --git a/core/src/test/java/org/apache/iceberg/deletes/TestBitmapPositionDeleteIndex.java b/core/src/test/java/org/apache/iceberg/deletes/TestBitmapPositionDeleteIndex.java index 76b294f80611..5281589427a0 100644 --- a/core/src/test/java/org/apache/iceberg/deletes/TestBitmapPositionDeleteIndex.java +++ b/core/src/test/java/org/apache/iceberg/deletes/TestBitmapPositionDeleteIndex.java @@ -19,6 +19,7 @@ package org.apache.iceberg.deletes; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; import java.io.IOException; import java.net.URL; @@ -176,6 +177,24 @@ public void testAllContainerTypesIndexSerialization() throws Exception { validate(index, "all-container-types-position-index.bin"); } + @Test + public void testDeserializeInvalidCrc() { + PositionDeleteIndex index = new BitmapPositionDeleteIndex(); + index.delete(1L); + index.delete(2L); + byte[] bytes = index.serialize().array(); + + // corrupt the last CRC byte so the computed checksum no longer matches + bytes[bytes.length - 1] ^= 0x01; + + DeleteFile dv = mockDV(bytes.length, index.cardinality()); + Mockito.when(dv.location()).thenReturn("s3://bucket/dv.puffin"); + + assertThatThrownBy(() -> PositionDeleteIndex.deserialize(bytes, dv)) + .isInstanceOf(IllegalArgumentException.class) + .hasMessageContaining("Invalid CRC for deletion vector s3://bucket/dv.puffin"); + } + private static void validate(PositionDeleteIndex index, String goldenFile) throws Exception { ByteBuffer buffer = index.serialize(); byte[] bytes = buffer.array();