{"record":{"id":"c3a84794f81c2a3d","repo":"apache/druid","slug":"maxconcurrentstagesperworker-must-be-positive","errorCode":null,"errorMessage":"maxConcurrentStagesPerWorker must be positive","messagePattern":"maxConcurrentStagesPerWorker must be positive","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"multi-stage-query/src/main/java/org/apache/druid/msq/kernel/controller/ControllerQueryKernelConfig.java","lineNumber":70,"sourceCode":"      boolean pipeline,\n      boolean durableStorage,\n      boolean faultTolerance,\n      MSQDestination destination,\n      @Nullable String controllerHost,\n      @Nullable List<String> workerIds,\n      Map<String, Object> workerContextMap\n  )\n  {\n    if (maxRetainedPartitionSketchBytes <= 0) {\n      throw new IAE(\"maxRetainedPartitionSketchBytes must be positive\");\n    }\n\n    if (pipeline && maxConcurrentStages < 2) {\n      throw new IAE(\"maxConcurrentStagesPerWorker must be >= 2 when pipelining\");\n    }\n\n    if (maxConcurrentStages <= 0) {\n      throw new IAE(\"maxConcurrentStagesPerWorker must be positive\");\n    }\n\n    if (pipeline && faultTolerance) {\n      throw new IAE(\"Cannot pipeline with fault tolerance\");\n    }\n\n    if (pipeline && durableStorage) {\n      throw new IAE(\"Cannot pipeline with durable storage\");\n    }\n\n    if (faultTolerance && !durableStorage) {\n      throw new IAE(\"Cannot have fault tolerance without durable storage\");\n    }\n\n    this.maxRetainedPartitionSketchBytes = maxRetainedPartitionSketchBytes;\n    this.maxConcurrentStages = maxConcurrentStages;\n    this.pipeline = pipeline;\n    this.durableStorage = durableStorage;","sourceCodeStart":52,"sourceCodeEnd":88,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/multi-stage-query/src/main/java/org/apache/druid/msq/kernel/controller/ControllerQueryKernelConfig.java#L52-L88","documentation":"maxConcurrentStages (maxConcurrentStagesPerWorker) must be at least 1; the constructor throws IAE when it is <= 0. A worker cannot run zero or negative concurrent stage slots, so this fails fast at kernel construction.","triggerScenarios":"Constructing ControllerQueryKernelConfig with maxConcurrentStages = 0 or negative, e.g. an unparsed/empty context value coerced to 0, or an invalid user-supplied value for maxConcurrentStagesPerWorker.","commonSituations":"Query context value 'maxConcurrentStagesPerWorker' set to 0 or a negative number by mistake; numeric parsing of empty string; bad tuning guidance copied into cluster defaults.","solutions":["Set maxConcurrentStages to a positive integer in the query context (default 2).","If limiting concurrency, use 1 (with pipelining off) rather than 0.","Guard programmatic construction: if (maxConcurrentStages <= 0) maxConcurrentStages = 2;"],"exampleFix":"// before\ncontext.put(\"maxConcurrentStagesPerWorker\", 0);\n\n// after\ncontext.put(\"maxConcurrentStagesPerWorker\", 2);","handlingStrategy":"validation","validationCode":"if (maxConcurrentStages <= 0) {\n  throw new IllegalArgumentException(\"maxConcurrentStagesPerWorker must be >= 1\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  kernelConfig = buildKernelConfig(ctx);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"must be positive\")) {\n    ctx.put(\"maxConcurrentStagesPerWorker\", 2);\n    kernelConfig = buildKernelConfig(ctx);\n  }\n}","preventionTips":["Treat 0/negative tuning values as typos: clamp to >= 1 before submission.","Validate numeric query-context values at submission time, not at controller runtime.","Use named constants for defaults instead of literal 0."],"tags":["msq","configuration","validation","iae"],"backgroundTag":"value-out-of-range","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"}