apache/druid · error · IllegalArgumentException

Not enough capacity for even one row! Need[%,d] but…

Error message

Not enough capacity for even one row! Need[%,d] but have[%,d].

What it means

ByteBufferHashTable.reset computes how many buckets fit in the allocated arena. If the buffer is too small to hold even a single bucket (key + hash + aggregator row + int offset), the table cannot store any row and reset throws an IAE before any grouping starts.

Solutions

  1. Increase the groupBy intermediate buffer size (druid.query.groupBy.intermediate.intermediateBufferSize / processing buffer sizes)
  2. Reduce the number/size of aggregators in the query
  3. Reduce group-key size (fewer/smaller dimensions, dictionary-encoded string keys)
  4. Increase initialBuckets headroom is not the issue here — ensure buffer capacity exceeds one full row; check bucketSize = HASH_SIZE + keySize + aggregators.spaceNeeded()

Example fix

// before
"druid.query.groupBy.bufferGrouperMaxSize": 1024 // too small for one row of this query
// after
"druid.query.groupBy.bufferGrouperMaxSize": 100000000 // ensure >= bucketSizeWithHash + 4 bytes; prefer raising processing buffer
Defensive patterns

Strategy: validation

Validate before calling

long bucketSizeWithHash = 4 + keySerde.keySize() + aggregators.spaceNeeded();
if (buffer.capacity() < bucketSizeWithHash + Integer.BYTES) {
  throw new IllegalArgumentException("groupBy buffer too small for one row: need " + (bucketSizeWithHash + 4));
}

Try / catch

try { table.reset(); } catch (IAE e) { if (e.getMessage().contains("Not enough capacity")) { increaseBufferSizeAndRetry(); } }

Prevention

When it happens

Trigger: Constructing a BufferHashGrouper/SpillingGrouper with a buffer whose capacity is smaller than bucketSizeWithHash + 4 bytes — i.e. bufferSize from druid.query.groupBy.bufferGrouperMaxSize... too small relative to key size plus aggregator spaceNeeded, or initialBuckets larger than what the arena fits (maxBuckets < 1).

Common situations: Very large row keys (high-cardinality multi-dim groupings, long strings) with a small groupBy buffer; many/large aggregators; low druid.processing.buffer.sizeBytes memory pressure.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/4c5d20ede2ce7df2. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/ByteBufferHashTable.java:135

    this.buffer = buffer;
    this.keySize = keySize;
    this.maxSizeForTesting = maxSizeForTesting;
    this.tableArenaSize = buffer.capacity();
    this.bucketUpdateHandler = bucketUpdateHandler;
    this.maxMergeBufferUsedBytes = 0;
    this.maxSpillProximity = 0.0;
    this.spillRegrowthThreshold = 0;
  }

  public void reset()
  {
    size = 0;

    maxBuckets = Math.min(tableArenaSize / bucketSizeWithHash, initialBuckets);
    regrowthThreshold = maxSizeForBuckets(maxBuckets);

    if (maxBuckets < 1) {
      throw new IAE(
          "Not enough capacity for even one row! Need[%,d] but have[%,d].",
          bucketSizeWithHash + Integer.BYTES,
          buffer.capacity()
      );
    }

    // Start table part-way through the buffer so the last growth can start from zero and thereby use more space.
    tableStart = initialTableStart(maxBuckets);

    final ByteBuffer bufferDup = buffer.duplicate();
    bufferDup.position(tableStart);
    bufferDup.limit(tableStart + maxBuckets * bucketSizeWithHash);
    tableBuffer = bufferDup.slice();
    updateMaxMergeBufferUsedBytes();

    // Clear used bits of new table
    for (int i = 0; i < maxBuckets; i++) {
      tableBuffer.putInt(i * bucketSizeWithHash, 0);

View on GitHub (pinned to 9b90983fd2)