{"record":{"id":"51d13536314968a0","repo":"apache/druid","slug":"taskcountmax-or-taskcountmin-can-t-be-null","errorCode":null,"errorMessage":"taskCountMax or taskCountMin can't be null!","messagePattern":"taskCountMax or taskCountMin can't be null!","errorType":"validation","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/supervisor/autoscaler/LagBasedAutoScalerConfig.java","lineNumber":99,"sourceCode":"          @Nullable @JsonProperty(\"stopTaskCountRatio\") Double stopTaskCountRatio\n  )\n  {\n    this.enableTaskAutoScaler = enableTaskAutoScaler != null ? enableTaskAutoScaler : false;\n    this.lagCollectionIntervalMillis = lagCollectionIntervalMillis != null ? lagCollectionIntervalMillis : 30000;\n    this.lagCollectionRangeMillis = lagCollectionRangeMillis != null ? lagCollectionRangeMillis : 600000;\n    this.scaleActionStartDelayMillis = scaleActionStartDelayMillis != null ? scaleActionStartDelayMillis : 300000;\n    this.scaleActionPeriodMillis = scaleActionPeriodMillis != null ? scaleActionPeriodMillis : 60000;\n    this.scaleOutThreshold = scaleOutThreshold != null ? scaleOutThreshold : 6000000;\n    this.scaleInThreshold = scaleInThreshold != null ? scaleInThreshold : 1000000;\n    this.triggerScaleOutFractionThreshold = triggerScaleOutFractionThreshold != null ? triggerScaleOutFractionThreshold : 0.3;\n    this.triggerScaleInFractionThreshold = triggerScaleInFractionThreshold != null ? triggerScaleInFractionThreshold : 0.9;\n    this.lagAggregate = lagAggregate;\n\n    // 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.\n    // If autoscaler is disabled, no matter what configs are set, they are not used.\n    if (this.enableTaskAutoScaler) {\n      if (taskCountMax == null || taskCountMin == null) {\n        throw new RuntimeException(\"taskCountMax or taskCountMin can't be null!\");\n      } else if (taskCountMax < taskCountMin) {\n        throw new RuntimeException(\"taskCountMax can't lower than taskCountMin!\");\n      } else if (taskCountStart != null && (taskCountStart > taskCountMax || taskCountStart < taskCountMin)) {\n        throw new RuntimeException(\"taskCountMin <= taskCountStart <= taskCountMax\");\n      }\n      this.taskCountMax = taskCountMax;\n      this.taskCountMin = taskCountMin;\n      this.taskCountStart = taskCountStart;\n    }\n\n    this.scaleInStep = scaleInStep != null ? scaleInStep : 1;\n    this.scaleOutStep = scaleOutStep != null ? scaleOutStep : 2;\n    this.minTriggerScaleActionFrequencyMillis =\n        minTriggerScaleActionFrequencyMillis != null ? minTriggerScaleActionFrequencyMillis : 600000;\n    this.minScaleUpDelay = Configs.valueOrDefault(minScaleUpDelay, Duration.millis(this.minTriggerScaleActionFrequencyMillis));\n    this.minScaleDownDelay = Configs.valueOrDefault(minScaleDownDelay, Duration.millis(this.minTriggerScaleActionFrequencyMillis));\n\n    Preconditions.checkArgument(","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/indexing-service/src/main/java/org/apache/druid/indexing/seekablestream/supervisor/autoscaler/LagBasedAutoScalerConfig.java#L81-L117","documentation":"LagBasedAutoScalerConfig validates that when the task autoscaler is enabled, taskCountMax and taskCountMin must be provided (and Max >= Min, Start within range). A plain RuntimeException is thrown when either is null, because the autoscaler cannot function without its scaling bounds. Leaving autoscaler disabled (empty autoConfig) bypasses this check.","triggerScenarios":"Constructing the config (e.g. from a supervisor spec's autoScalerConfig with enableTaskAutoScaler: true) where taskCountMax or taskCountMin is missing/null.","commonSituations":"Spec with \"autoScalerConfig\": {\"enableTaskAutoScaler\": true} but forgotten taskCountMax/taskCountMin; typo in property names; templated spec omitting the bounds; JSON casing mismatch so fields deserialized as null.","solutions":["Add both taskCountMax and taskCountMin to autoScalerConfig, with taskCountMax >= taskCountMin.","If you don't want autoscaling, set \"autoScalerConfig\": {} (or omit enableTaskAutoScaler) so the check is skipped.","Verify property names/casing in the spec so Jackson populates the fields rather than leaving them null."],"exampleFix":"// before\n\"autoScalerConfig\": {\n  \"enableTaskAutoScaler\": true,\n  \"taskCountMax\": 4\n}\n// after: provide both bounds\n\"autoScalerConfig\": {\n  \"enableTaskAutoScaler\": true,\n  \"taskCountMin\": 1,\n  \"taskCountMax\": 4,\n  \"taskCountStart\": 2\n}","handlingStrategy":"validation","validationCode":"if (autoScalerConfig.enableTaskAutoScaler &&\n    (autoScalerConfig.taskCountMax == null || autoScalerConfig.taskCountMin == null)) {\n    throw new IllegalArgumentException(\"taskCountMax and taskCountMin required when autoscaler enabled\");\n}","typeGuard":null,"tryCatchPattern":"try { buildConfig(spec); } catch (RuntimeException e) { if (e.getMessage().contains(\"taskCountMax or taskCountMin\")) { applyDefaultBounds(); } }","preventionTips":["Always set taskCountMin/taskCountMax when enabling the autoscaler","Leave autoConfig empty {} to disable cleanly","Check field name spelling/casing in specs"],"tags":["druid","autoscaler","config","validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}