apache/druid · error · IllegalStateException
bucketSize must be a power of two but was[%,d]
Error message
bucketSize must be a power of two but was[%,d]
What it means
FrontCodedIntArrayIndexed's constructor requires bucketSize to be a power of two (exactly one bit set) because bucket lookup uses bit-shift arithmetic. A non-power-of-two bucketSize in the header means the data is corrupt, misaligned, or was produced by incompatible code, so it throws ISE rather than producing wrong results.
Solutions
- Verify the segment file is not corrupted; reload or re-ingest the affected segment
- Confirm the buffer position and ByteOrder match the writer when deserializing (use the standard read() factory, not direct construction)
- Ensure the writer that produced the column used a validated power-of-two bucketSize
- If you construct this class directly, validate first: bucketSize > 0 && Integer.bitCount(bucketSize) == 1
Example fix
// before new FrontCodedIntArrayIndexed(buffer, order, 6, numValues, hasNull, offsetsPosition); // ISE // after int bucketSize = 4; // power of two, matching the writer new FrontCodedIntArrayIndexed(buffer, order, bucketSize, numValues, hasNull, offsetsPosition);
Defensive patterns
Strategy: validation
Validate before calling
if (bucketSize <= 0 || Integer.bitCount(bucketSize) != 1) {
throw new IllegalArgumentException("bucketSize must be a power of two: " + bucketSize);
} Try / catch
try {
FrontCodedIntArrayIndexed idx = FrontCodedIntArrayIndexed.read(buffer, order);
} catch (IllegalStateException e) {
// corrupted or misaligned buffer; reload or re-ingest the segment
} Prevention
- Use the standard read() factory for deserialization; avoid direct construction
- Validate power-of-two bucketSize on the writing side before serializing
- Check buffer offsets and ByteOrder when reading raw column buffers
- Treat this error as a corruption signal: restore the segment from backup or re-ingest
When it happens
Trigger: Reading a FrontCodedIntArrayIndexed whose header yields a bucketSize like 3, 5, or 6 — from a corrupted buffer, wrong buffer offset, byte-order mismatch, or directly constructing the object with an invalid bucketSize.
Common situations: Corrupted segment files (disk issues, truncated copies); reading an array-typed column with mismatched offset/order assumptions; custom/direct construction with an unvalidated bucketSize; version-skew reading segments written by incompatible writers.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- bucketSize must be a power of two but was[%,d]
- bucketSize must be a power of two (from 1 up to 128) but…
- integer values must be positive, got
- Unexpected null byte
- val[ ] > maxValue[ ], please don't lie about maxValue. i[ ]
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/489c65cdab462d0c.
Report an issue: GitHub.
Appendix: source
Thrown at processing/src/main/java/org/apache/druid/segment/data/FrontCodedIntArrayIndexed.java:124
private final int rem;
private final int offsetsPosition;
private final int bucketsPosition;
private final boolean hasNull;
private final int lastBucketNumValues;
private final int[] unwindPrefixLength;
private final int[] unwindBufferPosition;
private FrontCodedIntArrayIndexed(
ByteBuffer buffer,
ByteOrder order,
int bucketSize,
int numValues,
boolean hasNull,
int offsetsPosition
)
{
if (Integer.bitCount(bucketSize) != 1) {
throw new ISE("bucketSize must be a power of two but was[%,d]", bucketSize);
}
this.buffer = buffer.asReadOnlyBuffer().order(order);
this.bucketSize = bucketSize;
this.hasNull = hasNull;
this.numBuckets = (int) Math.ceil((double) numValues / (double) bucketSize);
this.adjustIndex = hasNull ? 1 : 0;
this.adjustedNumValues = numValues + adjustIndex;
this.div = Integer.numberOfTrailingZeros(bucketSize);
this.rem = bucketSize - 1;
this.lastBucketNumValues = (numValues & rem) == 0 ? bucketSize : numValues & rem;
this.offsetsPosition = offsetsPosition;
this.bucketsPosition = offsetsPosition + ((numBuckets - 1) * Integer.BYTES);
this.unwindPrefixLength = new int[bucketSize];
this.unwindBufferPosition = new int[bucketSize];
}
@OverrideView on GitHub (pinned to 9b90983fd2)