apache/druid · error · IllegalArgumentException

Invalid maxLoadFactor

Error message

Invalid maxLoadFactor[%f], must be < 1.0

What it means

BufferHashGrouper's maxLoadFactor controls how full the open-addressing hash table may get before regrouping. A value >= 1.0 would prevent the table from ever resizing safely, so the constructor rejects it with an IAE.

Solutions

  1. Set maxLoadFactor to a fraction in (0, 1.0), e.g. 0.7 (default 0.85+ ranges)
  2. Remove the explicit config so the DEFAULT_MAX_LOAD_FACTOR applies
  3. Validate the config value before constructing BufferHashGrouper
  4. If a percentage is being used, divide by 100

Example fix

// before
"maxLoadFactor": 1.0
// after
"maxLoadFactor": 0.7
Defensive patterns

Strategy: validation

Validate before calling

if (maxLoadFactor <= 0 || maxLoadFactor >= 1.0f) {
  throw new IllegalArgumentException("maxLoadFactor must be in (0, 1.0), got " + maxLoadFactor);
}

Type guard

boolean isValidLoadFactor(float f) { return f > 0f && f < 1.0f; }

Try / catch

try { new BufferHashGrouper(..., maxLoadFactor, ...); } catch (IAE e) { if (e.getMessage().contains("maxLoadFactor")) { log config error; use default; } }

Prevention

When it happens

Trigger: Configuring the groupBy buffer grouper with druid.query.groupBy.maxOnDiskStorage / buffer grouper maxLoadFactor settings (via GroupByQueryConfig or ByteBufferMatcher config) where maxLoadFactor <= 0 falls back to default but maxLoadFactor >= 1.0 throws — e.g. passing 1.0 or 1.5 in a JSON config override.

Common situations: Copy-pasting tuning configs with loadFactor 1.0 assuming 'use full buffer'; wrong units (percentage 100 vs fraction 1.0); auto-generated configs dividing by zero.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/BufferHashGrouper.java:70

  private ByteBufferIntList offsetList;

  public BufferHashGrouper(
      final Supplier<ByteBuffer> bufferSupplier,
      final KeySerde<KeyType> keySerde,
      final AggregatorAdapters aggregators,
      final int bufferGrouperMaxSize,
      final float maxLoadFactor,
      final int initialBuckets,
      final boolean useDefaultSorting
  )
  {
    super(bufferSupplier, keySerde, aggregators, HASH_SIZE + keySerde.keySize(), bufferGrouperMaxSize);

    this.maxLoadFactor = maxLoadFactor > 0 ? maxLoadFactor : DEFAULT_MAX_LOAD_FACTOR;
    this.initialBuckets = initialBuckets > 0 ? Math.max(MIN_INITIAL_BUCKETS, initialBuckets) : DEFAULT_INITIAL_BUCKETS;

    if (this.maxLoadFactor >= 1.0f) {
      throw new IAE("Invalid maxLoadFactor[%f], must be < 1.0", maxLoadFactor);
    }

    this.bucketSize = HASH_SIZE + keySerde.keySize() + aggregators.spaceNeeded();
    this.useDefaultSorting = useDefaultSorting;
  }

  @Override
  public void init()
  {
    if (!initialized) {
      ByteBuffer buffer = bufferSupplier.get();

      int hashTableSize = ByteBufferHashTable.calculateTableArenaSizeWithPerBucketAdditionalSize(
          buffer.capacity(),
          bucketSize,
          Integer.BYTES
      );

View on GitHub (pinned to 9b90983fd2)