{"record":{"id":"8ec1334f93b6d2a7","repo":"apache/druid","slug":"invalid-maxloadfactor-f-must-be-1-0","errorCode":null,"errorMessage":"Invalid maxLoadFactor[%f], must be < 1.0","messagePattern":"Invalid maxLoadFactor\\[(.+?)\\], must be < 1\\.0","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/BufferHashGrouper.java","lineNumber":70,"sourceCode":"  private ByteBufferIntList offsetList;\n\n  public BufferHashGrouper(\n      final Supplier<ByteBuffer> bufferSupplier,\n      final KeySerde<KeyType> keySerde,\n      final AggregatorAdapters aggregators,\n      final int bufferGrouperMaxSize,\n      final float maxLoadFactor,\n      final int initialBuckets,\n      final boolean useDefaultSorting\n  )\n  {\n    super(bufferSupplier, keySerde, aggregators, HASH_SIZE + keySerde.keySize(), bufferGrouperMaxSize);\n\n    this.maxLoadFactor = maxLoadFactor > 0 ? maxLoadFactor : DEFAULT_MAX_LOAD_FACTOR;\n    this.initialBuckets = initialBuckets > 0 ? Math.max(MIN_INITIAL_BUCKETS, initialBuckets) : DEFAULT_INITIAL_BUCKETS;\n\n    if (this.maxLoadFactor >= 1.0f) {\n      throw new IAE(\"Invalid maxLoadFactor[%f], must be < 1.0\", maxLoadFactor);\n    }\n\n    this.bucketSize = HASH_SIZE + keySerde.keySize() + aggregators.spaceNeeded();\n    this.useDefaultSorting = useDefaultSorting;\n  }\n\n  @Override\n  public void init()\n  {\n    if (!initialized) {\n      ByteBuffer buffer = bufferSupplier.get();\n\n      int hashTableSize = ByteBufferHashTable.calculateTableArenaSizeWithPerBucketAdditionalSize(\n          buffer.capacity(),\n          bucketSize,\n          Integer.BYTES\n      );\n","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/BufferHashGrouper.java#L52-L88","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set maxLoadFactor to a fraction in (0, 1.0), e.g. 0.7 (default 0.85+ ranges)","Remove the explicit config so the DEFAULT_MAX_LOAD_FACTOR applies","Validate the config value before constructing BufferHashGrouper","If a percentage is being used, divide by 100"],"exampleFix":"// before\n\"maxLoadFactor\": 1.0\n// after\n\"maxLoadFactor\": 0.7","handlingStrategy":"validation","validationCode":"if (maxLoadFactor <= 0 || maxLoadFactor >= 1.0f) {\n  throw new IllegalArgumentException(\"maxLoadFactor must be in (0, 1.0), got \" + maxLoadFactor);\n}","typeGuard":"boolean isValidLoadFactor(float f) { return f > 0f && f < 1.0f; }","tryCatchPattern":"try { new BufferHashGrouper(..., maxLoadFactor, ...); } catch (IAE e) { if (e.getMessage().contains(\"maxLoadFactor\")) { log config error; use default; } }","preventionTips":["Express load factors as fractions, never percentages","Add config schema validation for groupBy tuning keys","Document valid range (0, 1.0) in config examples"],"tags":["druid","groupby","configuration","hashtable"],"backgroundTag":"invalid-config-value","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"}