{"record":{"id":"4c5d20ede2ce7df2","repo":"apache/druid","slug":"not-enough-capacity-for-even-one-row-need-d-bu","errorCode":null,"errorMessage":"Not enough capacity for even one row! Need[%,d] but have[%,d].","messagePattern":"Not enough capacity for even one row! Need\\[%,d\\] but have\\[%,d\\]\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/ByteBufferHashTable.java","lineNumber":135,"sourceCode":"    this.buffer = buffer;\n    this.keySize = keySize;\n    this.maxSizeForTesting = maxSizeForTesting;\n    this.tableArenaSize = buffer.capacity();\n    this.bucketUpdateHandler = bucketUpdateHandler;\n    this.maxMergeBufferUsedBytes = 0;\n    this.maxSpillProximity = 0.0;\n    this.spillRegrowthThreshold = 0;\n  }\n\n  public void reset()\n  {\n    size = 0;\n\n    maxBuckets = Math.min(tableArenaSize / bucketSizeWithHash, initialBuckets);\n    regrowthThreshold = maxSizeForBuckets(maxBuckets);\n\n    if (maxBuckets < 1) {\n      throw new IAE(\n          \"Not enough capacity for even one row! Need[%,d] but have[%,d].\",\n          bucketSizeWithHash + Integer.BYTES,\n          buffer.capacity()\n      );\n    }\n\n    // Start table part-way through the buffer so the last growth can start from zero and thereby use more space.\n    tableStart = initialTableStart(maxBuckets);\n\n    final ByteBuffer bufferDup = buffer.duplicate();\n    bufferDup.position(tableStart);\n    bufferDup.limit(tableStart + maxBuckets * bucketSizeWithHash);\n    tableBuffer = bufferDup.slice();\n    updateMaxMergeBufferUsedBytes();\n\n    // Clear used bits of new table\n    for (int i = 0; i < maxBuckets; i++) {\n      tableBuffer.putInt(i * bucketSizeWithHash, 0);","sourceCodeStart":117,"sourceCodeEnd":153,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/ByteBufferHashTable.java#L117-L153","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Increase the groupBy intermediate buffer size (druid.query.groupBy.intermediate.intermediateBufferSize / processing buffer sizes)","Reduce the number/size of aggregators in the query","Reduce group-key size (fewer/smaller dimensions, dictionary-encoded string keys)","Increase initialBuckets headroom is not the issue here — ensure buffer capacity exceeds one full row; check bucketSize = HASH_SIZE + keySize + aggregators.spaceNeeded()"],"exampleFix":"// before\n\"druid.query.groupBy.bufferGrouperMaxSize\": 1024 // too small for one row of this query\n// after\n\"druid.query.groupBy.bufferGrouperMaxSize\": 100000000 // ensure >= bucketSizeWithHash + 4 bytes; prefer raising processing buffer","handlingStrategy":"validation","validationCode":"long bucketSizeWithHash = 4 + keySerde.keySize() + aggregators.spaceNeeded();\nif (buffer.capacity() < bucketSizeWithHash + Integer.BYTES) {\n  throw new IllegalArgumentException(\"groupBy buffer too small for one row: need \" + (bucketSizeWithHash + 4));\n}","typeGuard":null,"tryCatchPattern":"try { table.reset(); } catch (IAE e) { if (e.getMessage().contains(\"Not enough capacity\")) { increaseBufferSizeAndRetry(); } }","preventionTips":["Size groupBy buffers larger than max key + aggregator footprint","Avoid very wide grouping keys on memory-constrained brokers","Compute bucket size during query planning and fail fast with a clear message"],"tags":["druid","groupby","memory","buffer-capacity"],"backgroundTag":"value-out-of-range","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}