prestodb/presto · error · IllegalArgumentException

A null map must have zero entries

Error message

A null map must have zero entries

What it means

A MAP block whose isNull flag is set for a row must encode zero entries for that row (offsets[i+1] == offsets[i]). If a null map is declared but the offsets slice claims entries, the block would have key/value data for a null value, which is inconsistent, so the library throws IllegalArgumentException.

Source

Thrown at presto-common/src/main/java/com/facebook/presto/common/block/AbstractMapBlock.java:488

        {
            return INSTANCE_SIZE + sizeOf(hashTables);
        }

        public void loadHashTables(int positionCount, int[] offsets, boolean[] mapIsNull, Block keyBlock, MethodHandle keyBlockHashCode)
        {
            int[] hashTables = new int[keyBlock.getPositionCount() * HASH_MULTIPLIER];
            Arrays.fill(hashTables, -1);

            verify(positionCount < offsets.length, "incorrect offsets size");

            for (int i = 0; i < positionCount; i++) {
                int keyOffset = offsets[i];
                int keyCount = offsets[i + 1] - keyOffset;
                if (keyCount < 0) {
                    throw new IllegalArgumentException(format("Offset is not monotonically ascending. offsets[%s]=%s, offsets[%s]=%s", i, offsets[i], i + 1, offsets[i + 1]));
                }
                if (mapIsNull != null && mapIsNull[i] && keyCount != 0) {
                    throw new IllegalArgumentException("A null map must have zero entries");
                }
                buildHashTable(
                        keyBlock,
                        keyOffset,
                        keyCount,
                        keyBlockHashCode,
                        hashTables,
                        keyOffset * HASH_MULTIPLIER,
                        keyCount * HASH_MULTIPLIER);
            }
            set(hashTables);
        }

        // This class intentionally does not implement hashcode and equals.
        // Any class using Hashtables as a field (MapBlock, MapBlockBuilder) should not include this class's implementation as this is
        // derived data. Only using KeyBlock hashcode/equals should suffice.
        // This class has no immutable fields, which makes hashcode/equals error-prone.
    }

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Ensure that whenever mapIsNull[i] is true, offsets[i+1] is set equal to offsets[i] before building the block.
  2. Recompute the offsets array from the same source of truth (the per-row entry counts and null flags) rather than patching them independently.
  3. Check serialization round-trips: null flags and offsets must be written/read from the same stream version.
  4. Validate before construction: for each i, (!null || entryCount == 0).

Example fix

// before
mapIsNull[i] = true;
// offsets[i+1] left at 3, leaving 2 entries for the null map
// after
mapIsNull[i] = true;
offsets[i + 1] = offsets[i]; // null map must have zero entries
Defensive patterns

Strategy: validation

Validate before calling

static void validateNullMapOffsets(int[] offsets, boolean[] mapIsNull, int positionCount) {
    for (int i = 0; i < positionCount; i++) {
        if (mapIsNull != null && mapIsNull[i]) {
            checkArgument(offsets[i + 1] == offsets[i], "null map at %d must have zero entries", i);
        }
    }
}

Try / catch

try {
    Block mapBlock = buildMapBlock(keys, values, offsets, mapIsNull);
} catch (IllegalArgumentException e) {
    if (e.getMessage() != null && e.getMessage().contains("A null map must have zero entries")) {
        throw new DataCorruptionException("null map row carries entries", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Creating a map block where mapIsNull[i] is true but offsets[i+1] - offsets[i] != 0; typically from custom block construction or deserialization that sets null flags independently of the offsets array.

Common situations: Custom serializers writing null flags and offsets separately; connector code reusing offsets arrays from a previous non-null batch while adding null flags; version-mismatched page deserialization.

Related errors


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