{"record":{"id":"d6d3623107f8d2e2","repo":"prestodb/presto","slug":"offset-is-not-monotonically-ascending-offsets-s","errorCode":null,"errorMessage":"Offset is not monotonically ascending. offsets[%s]=%s, offsets[%s]=%s","messagePattern":"Offset is not monotonically ascending\\. offsets\\[(.+?)\\]=(.+?), offsets\\[(.+?)\\]=(.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"presto-common/src/main/java/com/facebook/presto/common/block/AbstractMapBlock.java","lineNumber":485,"sourceCode":"        }\n\n        public long getRetainedSizeInBytes()\n        {\n            return INSTANCE_SIZE + sizeOf(hashTables);\n        }\n\n        public void loadHashTables(int positionCount, int[] offsets, boolean[] mapIsNull, Block keyBlock, MethodHandle keyBlockHashCode)\n        {\n            int[] hashTables = new int[keyBlock.getPositionCount() * HASH_MULTIPLIER];\n            Arrays.fill(hashTables, -1);\n\n            verify(positionCount < offsets.length, \"incorrect offsets size\");\n\n            for (int i = 0; i < positionCount; i++) {\n                int keyOffset = offsets[i];\n                int keyCount = offsets[i + 1] - keyOffset;\n                if (keyCount < 0) {\n                    throw new IllegalArgumentException(format(\"Offset is not monotonically ascending. offsets[%s]=%s, offsets[%s]=%s\", i, offsets[i], i + 1, offsets[i + 1]));\n                }\n                if (mapIsNull != null && mapIsNull[i] && keyCount != 0) {\n                    throw new IllegalArgumentException(\"A null map must have zero entries\");\n                }\n                buildHashTable(\n                        keyBlock,\n                        keyOffset,\n                        keyCount,\n                        keyBlockHashCode,\n                        hashTables,\n                        keyOffset * HASH_MULTIPLIER,\n                        keyCount * HASH_MULTIPLIER);\n            }\n            set(hashTables);\n        }\n\n        // This class intentionally does not implement hashcode and equals.\n        // Any class using Hashtables as a field (MapBlock, MapBlockBuilder) should not include this class's implementation as this is","sourceCodeStart":467,"sourceCodeEnd":503,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-common/src/main/java/com/facebook/presto/common/block/AbstractMapBlock.java#L467-L503","documentation":"When building a MAP block, Presto requires the offsets array to be monotonically non-decreasing: offsets[i+1] must be >= offsets[i]. A negative entry count means the offsets went backwards, which would corrupt the key/value layout of the map block, so the library throws IllegalArgumentException during validation.","triggerScenarios":"Calling MapBlock.createBlockHelper / mapType block builders with a hand-built offsets array where offsets[i+1] < offsets[i], or constructing a map block from serialized pages whose offsets were corrupted or miscomputed.","commonSituations":"Custom Block serialization/deserialization code (e.g. custom connectors, Hive ORC/Parquet readers, or page transport across Presto versions) producing misaligned offsets arrays; off-by-one errors when slicing key blocks.","solutions":["Fix the code that builds the offsets array so each offsets[i+1] = offsets[i] + entryCount for that map, keeping the array non-decreasing.","Verify offsets[0] == 0 and offsets[length-1] == keyBlock.getPositionCount() before creating the block.","Check that all nodes/clients run the same Presto version so serialized pages are not reinterpreted with different offsets semantics.","If the error surfaces only after deserializing pages, validate offsets on the producer side before shipping the page."],"exampleFix":"// before\nint[] offsets = {0, 5, 3, 8}; // not monotonic\nMapBlock.createBlockHelper(type, keyBlock, valueBlock, offsets, hashTables, null);\n// after\nint[] offsets = {0, 3, 5, 8}; // non-decreasing","handlingStrategy":"validation","validationCode":"static void validateMapOffsets(int[] offsets, int positionCount) {\n    for (int i = 0; i < positionCount; i++) {\n        checkArgument(offsets[i + 1] >= offsets[i],\n            \"offsets must be non-decreasing: offsets[%d]=%d > offsets[%d]=%d\",\n            i, offsets[i], i + 1, offsets[i + 1]);\n    }\n    checkArgument(offsets[0] == 0, \"offsets[0] must be 0\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    Block mapBlock = buildMapBlock(keys, values, offsets);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"not monotonically ascending\")) {\n        throw new DataCorruptionException(\"invalid map offsets\", e);\n    }\n    throw e;\n}","preventionTips":["Always derive offsets from per-row entry counts in a single pass.","Assert offsets[0] == 0 and monotonicity in a debug build before block creation.","Use the standard MapBuilder/BlockBuilder APIs instead of hand-assembling offsets arrays."],"tags":["presto","block","map-block","offsets","illegal-argument"],"backgroundTag":"invalid-offsets-array","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"}