prestodb/presto · error · IllegalArgumentException

Expected value to contain a single position but has %s posit

Error message

Expected value to contain a single position but has %s positions

What it means

RunLengthEncodedBlock represents N repetitions of exactly one value, so its constructor requires value.getPositionCount() == 1. Passing a multi-position block is a contract violation; the library throws IllegalArgumentException including the actual count, since it cannot pick which position to repeat.

Source

Thrown at presto-common/src/main/java/com/facebook/presto/common/block/RunLengthEncodedBlock.java:55

    private static final int INSTANCE_SIZE = ClassLayout.parseClass(RunLengthEncodedBlock.class).instanceSize();

    public static Block create(Type type, Object value, int positionCount)
    {
        Block block = Utils.nativeValueToBlock(type, value);
        if (block instanceof RunLengthEncodedBlock) {
            block = ((RunLengthEncodedBlock) block).getValue();
        }
        return new RunLengthEncodedBlock(block, positionCount);
    }

    private final Block value;
    private final int positionCount;

    public RunLengthEncodedBlock(Block value, int positionCount)
    {
        requireNonNull(value, "value is null");
        if (value.getPositionCount() != 1) {
            throw new IllegalArgumentException(format("Expected value to contain a single position but has %s positions", value.getPositionCount()));
        }

        if (value instanceof RunLengthEncodedBlock) {
            this.value = ((RunLengthEncodedBlock) value).getValue();
        }
        else {
            this.value = value;
        }

        if (positionCount < 0) {
            throw new IllegalArgumentException("positionCount is negative");
        }

        this.positionCount = positionCount;
    }

    public Block getValue()
    {

View on GitHub (pinned to 55bb57d202)

Solutions

  1. Extract a single-position block first (e.g. value.getSingleValueBlock(0) or RunLengthEncodedBlock wrapping then unwrapping)
  2. If you have a multi-position block, wrap each position separately or build via a page transform
  3. Check value.getPositionCount() == 1 before constructing

Example fix

// before
RunLengthEncodedBlock rle = new RunLengthEncodedBlock(valuesBlock, count); // valuesBlock has N positions
// after
RunLengthEncodedBlock rle = new RunLengthEncodedBlock(valuesBlock.getSingleValueBlock(0), count);
Defensive patterns

Strategy: validation

Validate before calling

// before constructing an RLE block
if (value.getPositionCount() != 1) {
    throw new IllegalArgumentException("constant must be a single-position block, got " + value.getPositionCount());
}
RunLengthEncodedBlock rle = new RunLengthEncodedBlock(value, n);

Type guard

boolean isSinglePositionBlock(Block b) {
    return b.getPositionCount() == 1;
}

Try / catch

try {
    return new RunLengthEncodedBlock(value, n);
} catch (IllegalArgumentException e) {
    if (e.getMessage().startsWith("Expected value to contain a single position")) {
        return new RunLengthEncodedBlock(value.getSingleValueBlock(0), n);
    }
    throw e;
}

Prevention

When it happens

Trigger: Passing any Block with positionCount != 1 to new RunLengthEncodedBlock(value, n) — e.g. passing a whole page block or an array block instead of a single-position block.

Common situations: Building constant columns for joins/aggregations where the constant was taken from a multi-row block; misusing getRegion/getPositionBlock results that return multi-position blocks; connector code synthesizing constant columns for predicate pushdown.

Related errors


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