{"record":{"id":"2a17c708b2c4fa18","repo":"prestodb/presto","slug":"deserialized-singlemapblock-violates-invariants-k","errorCode":null,"errorMessage":"Deserialized SingleMapBlock violates invariants: key %d, value %d","messagePattern":"Deserialized SingleMapBlock violates invariants: key (.+?), value (.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"critical","filePath":"presto-common/src/main/java/com/facebook/presto/common/block/SingleMapBlockEncoding.java","lineNumber":74,"sourceCode":"            sliceOutput.appendInt(-1);\n        }\n    }\n\n    @Override\n    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);","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/prestodb/presto/blob/55bb57d202de3b926896fa966c2c4a44c779634e/presto-common/src/main/java/com/facebook/presto/common/block/SingleMapBlockEncoding.java#L56-L92","documentation":"SingleMapBlockEncoding.readBlock deserializes key and value blocks plus an optional hash table from a SliceInput. It validates that keyBlock and valueBlock have equal position counts, because every map entry needs one key and one value. A mismatch means the serialized stream is corrupted or written by an incompatible producer, so readBlock throws IllegalArgumentException with the offending counts.","triggerScenarios":"Reading a MapBlock from serialized page data where the key block's positionCount differs from the value block's positionCount (e.g. truncated stream, wrong byte offsets, cross-version serialization incompatibility, or data written by a buggy custom serializer).","commonSituations":"Exchange/spill file corruption, mixing Presto versions in a cluster (different block encodings), third-party connectors writing raw serialized blocks, network truncation.","solutions":["Verify all nodes run the same Presto version; roll back or upgrade to align serialization formats.","Re-generate the corrupted spill/exchange data or retry the query; if corruption recurs, check storage/network integrity.","If a custom serializer produced the bytes, fix the writer so it emits key and value blocks with identical position counts.","Add a checksum/validation layer on serialized pages to detect truncation early."],"exampleFix":"// before\n// writer emits keys and values from different sources\nSliceOutput out = ...;\nblockEncodings.writeBlock(out, keyBlock);\nblockEncodings.writeBlock(out, valueBlock.slice(0, keyBlock.getPositionCount() - 1)); // mismatch\n// after\ncheckState(keyBlock.getPositionCount() == valueBlock.getPositionCount());\nblockEncodings.writeBlock(out, keyBlock);\nblockEncodings.writeBlock(out, valueBlock);","handlingStrategy":"try-catch","validationCode":"// before decoding, sanity-check the serialized stream size\nif (sliceInput.available() < MIN_MAP_BLOCK_BYTES) {\n    throw new IOException(\"truncated map block payload\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    Block block = blockEncoding.readBlock(sliceInput);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Deserialized SingleMapBlock violates invariants\")) {\n        throw new CorruptedPageException(\"Discard/regenerate spill or exchange data; check cluster version skew\", e);\n    }\n    throw e;\n}","preventionTips":["Keep all cluster nodes on the same Presto version.","Enable checksums on spill/exchange storage to catch truncation.","Never hand-write block encodings; use the provided BlockEncodingSerde."],"tags":["presto","serialization","map-block","corruption","invariants"],"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"}