apache/druid · error · RuntimeException
taskCountMax can't lower than taskCountMin!
Error message
taskCountMax can't lower than taskCountMin!
What it means
LagBasedAutoScalerConfig validates its task-count fields when the task autoscaler is enabled. If taskCountMax is set lower than taskCountMin, the configuration is rejected at construction time with this RuntimeException, since the scaler cannot scale between a range whose bounds are inverted. Validation only runs when enableTaskAutoScaler is true, so an empty {} config is accepted.
Source
Thrown at indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/supervisor/autoscaler/LagBasedAutoScalerConfig.java:101
{
this.enableTaskAutoScaler = enableTaskAutoScaler != null ? enableTaskAutoScaler : false;
this.lagCollectionIntervalMillis = lagCollectionIntervalMillis != null ? lagCollectionIntervalMillis : 30000;
this.lagCollectionRangeMillis = lagCollectionRangeMillis != null ? lagCollectionRangeMillis : 600000;
this.scaleActionStartDelayMillis = scaleActionStartDelayMillis != null ? scaleActionStartDelayMillis : 300000;
this.scaleActionPeriodMillis = scaleActionPeriodMillis != null ? scaleActionPeriodMillis : 60000;
this.scaleOutThreshold = scaleOutThreshold != null ? scaleOutThreshold : 6000000;
this.scaleInThreshold = scaleInThreshold != null ? scaleInThreshold : 1000000;
this.triggerScaleOutFractionThreshold = triggerScaleOutFractionThreshold != null ? triggerScaleOutFractionThreshold : 0.3;
this.triggerScaleInFractionThreshold = triggerScaleInFractionThreshold != null ? triggerScaleInFractionThreshold : 0.9;
this.lagAggregate = lagAggregate;
// Only do taskCountMax and taskCountMin check when autoscaler is enabled. So that users left autoConfig empty{} will not throw any exception and autoscaler is disabled.
// If autoscaler is disabled, no matter what configs are set, they are not used.
if (this.enableTaskAutoScaler) {
if (taskCountMax == null || taskCountMin == null) {
throw new RuntimeException("taskCountMax or taskCountMin can't be null!");
} else if (taskCountMax < taskCountMin) {
throw new RuntimeException("taskCountMax can't lower than taskCountMin!");
} else if (taskCountStart != null && (taskCountStart > taskCountMax || taskCountStart < taskCountMin)) {
throw new RuntimeException("taskCountMin <= taskCountStart <= taskCountMax");
}
this.taskCountMax = taskCountMax;
this.taskCountMin = taskCountMin;
this.taskCountStart = taskCountStart;
}
this.scaleInStep = scaleInStep != null ? scaleInStep : 1;
this.scaleOutStep = scaleOutStep != null ? scaleOutStep : 2;
this.minTriggerScaleActionFrequencyMillis =
minTriggerScaleActionFrequencyMillis != null ? minTriggerScaleActionFrequencyMillis : 600000;
this.minScaleUpDelay = Configs.valueOrDefault(minScaleUpDelay, Duration.millis(this.minTriggerScaleActionFrequencyMillis));
this.minScaleDownDelay = Configs.valueOrDefault(minScaleDownDelay, Duration.millis(this.minTriggerScaleActionFrequencyMillis));
Preconditions.checkArgument(
stopTaskCountRatio == null || (stopTaskCountRatio > 0.0 && stopTaskCountRatio <= 1.0),
"0.0 < stopTaskCountRatio <= 1.0"View on GitHub (pinned to 9b90983fd2)
Solutions
- Swap or correct taskCountMax and taskCountMin so taskCountMax >= taskCountMin in the supervisor spec
- Validate the bounds in your deployment tooling before submitting the supervisor spec
- If you don't want scaling, set enableTaskAutoScaler=false or leave the autoscaler block empty {}
Example fix
// before "taskCountMin": 4, "taskCountMax": 2 // after "taskCountMin": 2, "taskCountMax": 4
Defensive patterns
Strategy: validation
Validate before calling
if (cfg.enableTaskAutoScaler) {
if (cfg.taskCountMax == null || cfg.taskCountMin == null) throw new IllegalArgumentException("taskCountMax/taskCountMin required");
if (cfg.taskCountMax < cfg.taskCountMin) throw new IllegalArgumentException("taskCountMax must be >= taskCountMin");
} Try / catch
try { supervisor.start(spec); } catch (RuntimeException e) { if (e.getMessage().contains("taskCountMax")) { fixBoundsAndResubmit(); } else { throw e; } } Prevention
- Always define taskCountMax >= taskCountMin in autoscaler specs
- Validate supervisor JSON with a schema linter before submission
- Centralize autoscaler defaults in one template
When it happens
Trigger: Constructing a LagBasedAutoScalerConfig (or supplying supervisor autoscaler properties, e.g. Kafka/Kinesis taskCountMax/taskCountMin) with enableTaskAutoScaler=true and a taskCountMax value numerically less than taskCountMin.
Common situations: Hand-edited supervisor spec JSON where min/max are swapped or typos like max=2, min=4; programmatically generated configs computing max from a wrong variable; copying configs between supervisors without adjusting bounds.
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
- taskCountMax or taskCountMin can't be null!
- taskCountMin <= taskCountStart <= taskCountMax
- Cannot simultaneously replace and append to existing segment
- Interval[%s] is empty, must specify a nonempty interval
- SeekableStreamSupervisorIOConfig does not support both prope
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/5b2d24668cf789ce.
Report an issue: GitHub.