{"record":{"id":"d6addf7bdcdea642","repo":"apache/druid","slug":"invalid-maxloadfactor-f-must-be-1-0-d6addf","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/LimitedBufferHashGrouper.java","lineNumber":85,"sourceCode":"  public LimitedBufferHashGrouper(\n      final Supplier<ByteBuffer> bufferSupplier,\n      final Grouper.KeySerde<KeyType> keySerde,\n      final AggregatorAdapters aggregators,\n      final int bufferGrouperMaxSize,\n      final float maxLoadFactor,\n      final int initialBuckets,\n      final int limit,\n      final boolean sortHasNonGroupingFields\n  )\n  {\n    super(bufferSupplier, keySerde, aggregators, HASH_SIZE + keySerde.keySize(), bufferGrouperMaxSize);\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    this.limit = limit;\n    this.sortHasNonGroupingFields = sortHasNonGroupingFields;\n\n    if (this.maxLoadFactor >= 1.0f) {\n      throw new IAE(\"Invalid maxLoadFactor[%f], must be < 1.0\", maxLoadFactor);\n    }\n\n    // For each bucket, store an extra field indicating the bucket's current index within the heap when\n    // pushing down limits (size Integer.BYTES).\n    this.bucketSize = HASH_SIZE + keySerde.keySize() + Integer.BYTES + aggregators.spaceNeeded();\n  }\n\n  @Override\n  public void init()\n  {\n    if (initialized) {\n      return;\n    }\n    this.totalBuffer = bufferSupplier.get();\n\n    // We check this already in SpillingGrouper to ensure that LimitedBufferHashGrouper is only used when there is\n    // sufficient buffer capacity. If this error occurs, something went very wrong.\n    if (!validateBufferCapacity(totalBuffer.capacity())) {","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/query/groupby/epinephelinae/LimitedBufferHashGrouper.java#L67-L103","documentation":"Constructor validation in LimitedBufferHashGrouper: same invariant as HashVectorGrouper — maxLoadFactor must be strictly less than 1.0 because the heap-backed limited hash table needs free buckets to function. Values >= 1.0f throw this IAE; non-positive values are silently replaced with DEFAULT_MAX_LOAD_FACTOR, so only values in [1.0, inf) fail.","triggerScenarios":"Creating a LimitedBufferHashGrouper with maxLoadFactor >= 1.0f, typically via groupBy limit push-down configuration or programmatic construction for spilling/limit-limited group-bys.","commonSituations":"Tuning groupBy query server config (druid.query.groupBy.maxOnDiskStorage / load factor related knobs); misconfiguring fractional values as percentages (100 instead of 1.0-scale).","solutions":["Lower maxLoadFactor below 1.0 (0.5-0.9 is typical).","Fix units if the value came from a percent config (e.g. 95% -> 0.95, not 95 or 100).","Add an upstream config validator that rejects/clamps values >= 1.0 before engine startup."],"exampleFix":"// before\nclass: \"...\", maxLoadFactor: 1.0\n// after\nmaxLoadFactor: 0.8","handlingStrategy":"validation","validationCode":"if (!(maxLoadFactor > 0.0f && maxLoadFactor < 1.0f)) {\n  maxLoadFactor = 0.8f; // or reject\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Clamp load-factor config values at the config-loading layer","Document that 1.0 and above are invalid, not 'fully packed'","Watch for unit confusion between percent and fraction formats"],"tags":["druid","group-by","hash-table","config"],"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-14T05:17:10.506Z"}