{"record":{"id":"c8933fa13a8547bc","repo":"prestodb/presto","slug":"deserialized-singlemapblock-violates-invariants-e","errorCode":null,"errorMessage":"Deserialized SingleMapBlock violates invariants: expected hashtable size %d, actual hashtable size %d","messagePattern":"Deserialized SingleMapBlock violates invariants: expected hashtable size (.+?), actual hashtable size (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"critical","filePath":"presto-common/src/main/java/com/facebook/presto/common/block/SingleMapBlockEncoding.java","lineNumber":79,"sourceCode":"    public Block readBlock(BlockEncodingSerde blockEncodingSerde, SliceInput sliceInput)\n    {\n        Block keyBlock = blockEncodingSerde.readBlock(sliceInput);\n        Block valueBlock = blockEncodingSerde.readBlock(sliceInput);\n\n        int hashTableLength = sliceInput.readInt();\n        int[] hashTable = null;\n        if (hashTableLength >= 0) {\n            hashTable = new int[hashTableLength];\n            sliceInput.readBytes(wrappedIntArray(hashTable));\n        }\n\n        if (keyBlock.getPositionCount() != valueBlock.getPositionCount()) {\n            throw new IllegalArgumentException(\n                    format(\"Deserialized SingleMapBlock violates invariants: key %d, value %d\", keyBlock.getPositionCount(), valueBlock.getPositionCount()));\n        }\n\n        if (hashTable != null && keyBlock.getPositionCount() * HASH_MULTIPLIER != hashTable.length) {\n            throw new IllegalArgumentException(\n                    format(\"Deserialized SingleMapBlock violates invariants: expected hashtable size %d, actual hashtable size %d\", keyBlock.getPositionCount() * HASH_MULTIPLIER, hashTable.length));\n        }\n\n        MapBlock mapBlock = MapBlock.createMapBlockInternal(\n                0,\n                1,\n                Optional.empty(),\n                new int[] {0, keyBlock.getPositionCount()},\n                keyBlock,\n                valueBlock,\n                new HashTables(Optional.ofNullable(hashTable), 1));\n\n        return new SingleMapBlock(0, 0, keyBlock.getPositionCount() * 2, mapBlock);\n    }\n}\n","sourceCodeStart":61,"sourceCodeEnd":95,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-common/src/main/java/com/facebook/presto/common/block/SingleMapBlockEncoding.java#L61-L95","documentation":"SingleMapBlockEncoding.readBlock validates that the deserialized hash table's length equals keyBlock.getPositionCount() * HASH_MULTIPLIER. The hash table is a fixed-size open-addressing structure sized proportionally to the entry count; any other size means the stream is malformed or from an incompatible producer, so readBlock throws IllegalArgumentException with expected vs actual size.","triggerScenarios":"Deserializing a MapBlock where hashTables length != keyBlock.getPositionCount() * HASH_MULTIPLIER — corrupted spill/exchange bytes, wrong HASH_MULTIPLIER version skew between writer and reader, or a custom serializer emitting a wrong-sized hash table.","commonSituations":"Cluster nodes on different Presto versions exchanging pages, truncated spill files, hand-rolled connectors writing MapBlock encoding manually.","solutions":["Align Presto versions across all cluster nodes to fix HASH_MULTIPLIER/encoding skew.","Regenerate corrupted spill or exchange data; check disk and network reliability.","If writing the encoding manually, size the hash table as positionCount * HASH_MULTIPLIER.","Retry the operation and enable checksums to surface corruption earlier."],"exampleFix":"// before\nint[] hashTable = new int[keyBlock.getPositionCount()]; // wrong size\n// after\nint[] hashTable = new int[keyBlock.getPositionCount() * HASH_MULTIPLIER];","handlingStrategy":"try-catch","validationCode":"// writer-side pre-check\nint expected = keyBlock.getPositionCount() * HASH_MULTIPLIER;\nif (hashTables != null && hashTables.length != expected) {\n    throw new IllegalStateException(\"hash table size \" + hashTables.length + \" != expected \" + expected);\n}","typeGuard":null,"tryCatchPattern":"try {\n    Block block = blockEncoding.readBlock(sliceInput);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"expected hashtable size\")) {\n        throw new CorruptedPageException(\"Map block hashtable size mismatch — version skew or corrupted data\", e);\n    }\n    throw e;\n}","preventionTips":["Size hash tables as positionCount * HASH_MULTIPLIER whenever constructing MapBlocks.","Align Presto versions across nodes before rolling upgrades of spill/exchange formats.","Validate serialized payloads with checksums and regenerate corrupted data."],"tags":["presto","serialization","map-block","hashtable","corruption"],"backgroundTag":"deserialization-invariant-violation","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"}