elastic/elasticsearch · error · IllegalArgumentException

blockSize must be a power of 2 in [{}, {}], got: {}

Error message

blockSize must be a power of 2 in [{}, {}], got: {}

What it means

Thrown by the ColumNARDocValuesFormat constructor when blockSize fails any of three checks: below MIN_BLOCK_SIZE (128), above MAX_BLOCK_SIZE (8192), or not a power of two (the classic `n & (n-1) != 0` test). Block size bounds O(blockSize) per-field encoder allocations, and power-of-two is required by the bit-packing terminal. The SPI/no-arg constructor uses DEFAULT_BLOCK_SIZE (128); only explicit construction can hit this.

Source

Thrown at libs/columnar/src/main/java/org/elasticsearch/columnar/ColumNARDocValuesFormat.java:64

    static final String DATA_CODEC = "ColumNARNumericData";
    static final String DATA_EXTENSION = "cnvd";
    static final String META_CODEC = "ColumNARNumericMeta";
    static final String META_EXTENSION = "cnvm";

    private final NumericPipelineSelector pipelineSelector;
    private final int blockSize;

    /**
     * Constructs the format with a custom per-field pipeline selector and an explicit block size.
     * The block size controls how many values are grouped into each encoded block; it must be a
     * power of 2 between {@value #MIN_BLOCK_SIZE} and {@value #MAX_BLOCK_SIZE} inclusive.
     *
     * @throws IllegalArgumentException if {@code blockSize} is not a power of 2 in [{@value #MIN_BLOCK_SIZE}, {@value #MAX_BLOCK_SIZE}]
     */
    public ColumNARDocValuesFormat(NumericPipelineSelector pipelineSelector, int blockSize) {
        super(ColumnarFormat.NAME);
        if (blockSize < MIN_BLOCK_SIZE || blockSize > MAX_BLOCK_SIZE || (blockSize & (blockSize - 1)) != 0) {
            throw new IllegalArgumentException(
                "blockSize must be a power of 2 in [" + MIN_BLOCK_SIZE + ", " + MAX_BLOCK_SIZE + "], got: " + blockSize
            );
        }
        this.pipelineSelector = pipelineSelector;
        this.blockSize = blockSize;
    }

    /** Constructs the format with a custom per-field pipeline selector and the default block size. */
    public ColumNARDocValuesFormat(NumericPipelineSelector pipelineSelector) {
        this(pipelineSelector, DEFAULT_BLOCK_SIZE);
    }

    /** SPI constructor. Uses the default pipeline for every field. */
    public ColumNARDocValuesFormat() {
        this((fieldName, type) -> NumericPipeline::defaultPipeline);
    }

    @Override

View on GitHub (pinned to db6a809a66)

Solutions

  1. Use one of the documented powers of two in [128, 8192]: 128, 256, 512, 1024, 2048, 4096, 8192.
  2. Prefer the no-arg/SPI constructor or the single-arg constructor, which use DEFAULT_BLOCK_SIZE (128).
  3. If accepting user input, validate: `Integer.bitCount(blockSize) == 1 && blockSize >= 128 && blockSize <= 8192` before constructing.
  4. Round the requested size up to the next power of two and clamp into [128, 8192].

Example fix

// before
new ColumNARDocValuesFormat(selector, 1000); // throws

// after
new ColumNARDocValuesFormat(selector, 1024); // valid power of two in range
Defensive patterns

Strategy: validation

Validate before calling

void requireValidBlockSize(int blockSize) {
    if (Integer.bitCount(blockSize) != 1
        || blockSize < ColumNARDocValuesFormat.MIN_BLOCK_SIZE
        || blockSize > ColumNARDocValuesFormat.MAX_BLOCK_SIZE) {
        throw new IllegalArgumentException("blockSize must be a power of 2 in [128, 8192], got: " + blockSize);
    }
}

Type guard

static boolean isValidBlockSize(int blockSize) {
    return Integer.bitCount(blockSize) == 1
        && blockSize >= ColumNARDocValuesFormat.MIN_BLOCK_SIZE
        && blockSize <= ColumNARDocValuesFormat.MAX_BLOCK_SIZE;
}

Try / catch

try {
    return new ColumNARDocValuesFormat(selector, blockSize);
} catch (IllegalArgumentException e) {
    // fall back to the documented default rather than propagating a misconfiguration
    return new ColumNARDocValuesFormat(selector); // uses DEFAULT_BLOCK_SIZE = 128

Prevention

When it happens

Trigger: Constructing `new ColumNARDocValuesFormat(selector, blockSize)` with values like 100 (below min), 9000 (above max), 1000 (not power of two), 256 (valid), or 8192 (valid). Also if a codec is instantiated reflectively/SPI from a config string parsed to an invalid int.

Common situations: A test tuning block size for benchmarking and guessing a value. Config plumbing that forwards a user int without validating the power-of-two constraint. Migrating a Lucene codecs param (where 1–512 ranges are common) without re-scaling to ColumNAR's 128–8192 range.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/6de84dfff511ba07. Report an issue: GitHub.