prestodb/presto · critical · IllegalArgumentException

Deserialized SingleMapBlock violates invariants: key %d, val

Error message

Deserialized SingleMapBlock violates invariants: key %d, value %d

What it means

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.

Source

Thrown at presto-common/src/main/java/com/facebook/presto/common/block/SingleMapBlockEncoding.java:74

            sliceOutput.appendInt(-1);
        }
    }

    @Override
    public Block readBlock(BlockEncodingSerde blockEncodingSerde, SliceInput sliceInput)
    {
        Block keyBlock = blockEncodingSerde.readBlock(sliceInput);
        Block valueBlock = blockEncodingSerde.readBlock(sliceInput);

        int hashTableLength = sliceInput.readInt();
        int[] hashTable = null;
        if (hashTableLength >= 0) {
            hashTable = new int[hashTableLength];
            sliceInput.readBytes(wrappedIntArray(hashTable));
        }

        if (keyBlock.getPositionCount() != valueBlock.getPositionCount()) {
            throw new IllegalArgumentException(
                    format("Deserialized SingleMapBlock violates invariants: key %d, value %d", keyBlock.getPositionCount(), valueBlock.getPositionCount()));
        }

        if (hashTable != null && keyBlock.getPositionCount() * HASH_MULTIPLIER != hashTable.length) {
            throw new IllegalArgumentException(
                    format("Deserialized SingleMapBlock violates invariants: expected hashtable size %d, actual hashtable size %d", keyBlock.getPositionCount() * HASH_MULTIPLIER, hashTable.length));
        }

        MapBlock mapBlock = MapBlock.createMapBlockInternal(
                0,
                1,
                Optional.empty(),
                new int[] {0, keyBlock.getPositionCount()},
                keyBlock,
                valueBlock,
                new HashTables(Optional.ofNullable(hashTable), 1));

        return new SingleMapBlock(0, 0, keyBlock.getPositionCount() * 2, mapBlock);

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Verify all nodes run the same Presto version; roll back or upgrade to align serialization formats.
  2. Re-generate the corrupted spill/exchange data or retry the query; if corruption recurs, check storage/network integrity.
  3. If a custom serializer produced the bytes, fix the writer so it emits key and value blocks with identical position counts.
  4. Add a checksum/validation layer on serialized pages to detect truncation early.

Example fix

// before
// writer emits keys and values from different sources
SliceOutput out = ...;
blockEncodings.writeBlock(out, keyBlock);
blockEncodings.writeBlock(out, valueBlock.slice(0, keyBlock.getPositionCount() - 1)); // mismatch
// after
checkState(keyBlock.getPositionCount() == valueBlock.getPositionCount());
blockEncodings.writeBlock(out, keyBlock);
blockEncodings.writeBlock(out, valueBlock);
Defensive patterns

Strategy: try-catch

Validate before calling

// before decoding, sanity-check the serialized stream size
if (sliceInput.available() < MIN_MAP_BLOCK_BYTES) {
    throw new IOException("truncated map block payload");
}

Try / catch

try {
    Block block = blockEncoding.readBlock(sliceInput);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Deserialized SingleMapBlock violates invariants")) {
        throw new CorruptedPageException("Discard/regenerate spill or exchange data; check cluster version skew", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: 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).

Common situations: Exchange/spill file corruption, mixing Presto versions in a cluster (different block encodings), third-party connectors writing raw serialized blocks, network truncation.

Related errors


AI-assisted analysis of prestodb/presto@55bb57d202 (2026-09-04). Data as JSON: /api/errors/2a17c708b2c4fa18. Report an issue: GitHub.