{"record":{"id":"12ee6528c2279da0","repo":"prestodb/presto","slug":"invalid-row-block-12ee65","errorCode":null,"errorMessage":"Invalid row block","messagePattern":"Invalid row block","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"presto-common/src/main/java/com/facebook/presto/common/block/ColumnarRow.java","lineNumber":116,"sourceCode":"                // 3) the estimated serialized size for the fields Blocks which were just constructed as new DictionaryBlocks:\n                //     the average row size: averageRowSize * the number of rows: nonNullPositionCount\n                (Integer.BYTES + Byte.BYTES) * positionCount + averageRowSize * nonNullPositionCount);\n    }\n\n    private static ColumnarRow toColumnarRow(RunLengthEncodedBlock rleBlock)\n    {\n        Block rleValue = rleBlock.getValue();\n        int positionCount = rleBlock.getPositionCount();\n        ColumnarRow columnarRow = toColumnarRow(rleValue);\n\n        Block[] fields = new Block[columnarRow.getFieldCount()];\n        long averageRowSize = 0;\n        for (int i = 0; i < columnarRow.getFieldCount(); i++) {\n            Block nullSuppressedField = columnarRow.getField(i);\n            if (rleValue.isNull(0)) {\n                // the rle value is a null row so, all null-suppressed fields should empty\n                if (nullSuppressedField.getPositionCount() != 0) {\n                    throw new IllegalArgumentException(\"Invalid row block\");\n                }\n                fields[i] = nullSuppressedField;\n            }\n            else {\n                fields[i] = new RunLengthEncodedBlock(nullSuppressedField, positionCount);\n                averageRowSize += nullSuppressedField.getSizeInBytes() / nullSuppressedField.getPositionCount();\n            }\n        }\n        return new ColumnarRow(\n                rleBlock,\n                fields,\n                INSTANCE_SIZE + rleBlock.getRetainedSizeInBytes(),\n                // The estimated serialized size is the sum of the following:\n                // 1) the offsets size: Integer.BYTES * positionCount. Note that even though ColumnarRow doesn't have the offsets array, the serialized RowBlock still has it. Please see RowBlockEncodingBuffer.\n                // 2) nulls array size: Byte.BYTES * positionCount\n                // 3) the estimated serialized size for the fields Blocks which were just constructed as new RunLengthEncodedBlocks:\n                //     the average row size: averageRowSize * the number of rows: positionCount\n                (Integer.BYTES + Byte.BYTES) * positionCount + averageRowSize * positionCount);","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-common/src/main/java/com/facebook/presto/common/block/ColumnarRow.java#L98-L134","documentation":"When converting a RunLengthEncodedBlock containing a single row value into a columnar row, a NULL row must have every null-suppressed field block empty (0 positions). If any field of a null RLE row has a non-zero position count, the block is structurally inconsistent and IllegalArgumentException(\"Invalid row block\") is thrown. This indicates corrupted or incorrectly constructed nested blocks.","triggerScenarios":"Calling ColumnarRow.toColumnarRow / columnarRow on a RunLengthEncodedBlock whose single value is a NULL row but whose internal field blocks contain a non-zero number of positions — i.e. a malformed RLE-wrapped row block produced by a writer or deserializer.","commonSituations":"Custom serializers building RLE row blocks with mismatched field lengths; corrupted intermediate data from a connector; bugs in code that wraps a null row into RunLengthEncodedBlock without emptying field blocks.","solutions":["Fix the producer so a NULL row's RLE block wraps field blocks with positionCount 0","Rebuild the RLE block using RunLengthEncodedBlock(valueBlock, positionCount) from a properly formed row block instead of hand-assembling fields","Validate the source data/page upstream to catch malformed blocks before conversion","If the RLE value is non-null, ensure each field block has exactly 1 position (the loop divides by positionCount later)","Report/inspect the connector or codec that emitted the block, since this is data corruption, not user input"],"exampleFix":"// before — building RLE row block from a null row with leftover fields\nBlock[] nonEmptyFields = existingFields; // fields still hold positions\nRunLengthEncodedBlock rle = new RunLengthEncodedBlock(new RowBlockBuilder(...).build(), 1);\n// after — empty field blocks for a null row\nRowBlockBuilder builder = new RowBlockBuilder(fieldTypes, null, 1);\nbuilder.buildEntry(b -> { for (Type t : fieldTypes) { b.appendNull(); } });\nRunLengthEncodedBlock rle = new RunLengthEncodedBlock(builder.build(), positionCount);","handlingStrategy":"validation","validationCode":"static void validateRleRowBlock(RunLengthEncodedBlock rleValue, ColumnarRow columnarRow) {\n    for (int i = 0; i < columnarRow.getFieldCount(); i++) {\n        Block field = columnarRow.getField(i);\n        if (rleValue.isNull(0) && field.getPositionCount() != 0) {\n            throw new IllegalArgumentException(\"Field \" + i + \" of null RLE row must be empty\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    ColumnarRow row = ColumnarRow.toColumnarRow(rleBlock);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().equals(\"Invalid row block\")) {\n        throw new corruptPageException(\"Malformed RLE row block: null row with non-empty fields\");\n    }\n    throw e;\n}","preventionTips":["Never hand-assemble RLE row blocks; build row values with RowBlockBuilder","For null rows, emit empty field blocks (0 positions)","Validate writer output against reader expectations in connector tests","Treat this exception as data corruption — verify the upstream producer, not the caller"],"tags":["block","row","run-length-encoded","corrupt-data","presto"],"backgroundTag":"invalid-block-type","analyzedSha":"55bb57d202de3b926896fa966c2c4a44c779634e","analyzedAt":"2026-09-04T12:50:26.162Z","contentChangedAt":"2026-09-04T12:50:26.162Z","schemaVersion":2},"datasetVersion":"2026-09-11T21:17:09.523Z"}