{"record":{"id":"0daf0db400c31ed5","repo":"apache/druid","slug":"invalid-level-d","errorCode":null,"errorMessage":"Invalid level %d","messagePattern":"Invalid level (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/frame/processor/SuperSorter.java","lineNumber":920,"sourceCode":"    superSorterProgressTracker.setTotalMergingLevels(totalMergingLevels);\n  }\n\n  private ClusterByPartitions getOutputPartitions()\n  {\n    if (!outputPartitionsFuture.isDone()) {\n      throw new ISE(\"Output partitions are not ready yet\");\n    }\n\n    return FutureUtils.getUnchecked(outputPartitionsFuture, true);\n  }\n\n  @GuardedBy(\"runWorkersLock\")\n  private long getTotalMergersInLevel(final int level)\n  {\n    if (totalInputFrames == UNKNOWN_TOTAL || totalMergingLevels == UNKNOWN_LEVEL) {\n      return UNKNOWN_TOTAL;\n    } else if (level >= totalMergingLevels) {\n      throw new ISE(\"Invalid level %d\", level);\n    } else if (level == totalMergingLevels - 1) {\n      if (outputPartitionsFuture.isDone()) {\n        return totalInputFrames == 0 ? 0 : getOutputPartitions().size();\n      } else {\n        return UNKNOWN_TOTAL;\n      }\n    } else if (level > 0 && level == totalMergingLevels - 2) {\n      if (outputPartitionsFuture.isDone()) {\n        // Smallest number of mergers we can possibly use in the penultimate level.\n        final long totalInputs = getTotalMergersInLevel(level - 1);\n        final long minMergers =\n            LongMath.divide(totalInputs, maxChannelsPerMerger, RoundingMode.CEILING);\n\n        // Ensure we have a maximal degree of parallelism: possibly use more mergers than minMergers.\n        long targetNumMergers = Math.max(\n            minMergers,\n            Math.min(\n                maxActiveProcessors,","sourceCodeStart":902,"sourceCodeEnd":938,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/frame/processor/SuperSorter.java#L902-L938","documentation":"SuperSorter.getTotalMergersInLevel throws this IllegalStateException when asked for the merger count of a level that is greater than or equal to the total number of merging levels. Valid levels are 0 to totalMergingLevels-1; requesting anything higher means a caller is indexing beyond the defined sort hierarchy. This is an internal consistency check within the frame-processor SuperSorter machinery, not an expected user-facing failure.","triggerScenarios":"Calling getTotalMergersInLevel(level) where level >= totalMergingLevels, or when totalMergingLevels logic in one of its callers (setAllDoneIfPossible, runNextDirectMerger, totalInputs, runNextMiddleMerger, runNextUltimateMerger) computes an off-by-one or uninitialized level value.","commonSituations":"Developers modifying SuperSorter or writing custom frame processors that drive the sorter pass a level derived from their own bookkeeping that no longer matches the sorter's level count; also seen when totalInputFrames/totalMergingLevels were set after merge scheduling already started, leading to stale level indices.","solutions":["Verify totalMergingLevels was set (via SuperSorterProgressTracker.setTotalMergingLevels) before any level-indexed merge scheduling begins.","Check that all level arithmetic is exclusive of the total: valid levels are 0..totalMergingLevels-1; fix any off-by-one comparisons such as level <= totalMergingLevels.","Ensure callers handle the UNKNOWN_LEVEL sentinel instead of passing it as a concrete level value.","If the exception is reproducible with a fixed query shape, capture the stateString() log output and report the bug with the query's partitioning/sorting configuration."],"exampleFix":"// before\nfor (int level = 0; level <= totalMergingLevels; level++) {\n  long mergers = getTotalMergersInLevel(level);\n}\n// after\nfor (int level = 0; level < totalMergingLevels; level++) {\n  long mergers = getTotalMergersInLevel(level);\n}","handlingStrategy":"validation","validationCode":"if (totalMergingLevels != SuperSorter.UNKNOWN_LEVEL && level >= 0 && level < totalMergingLevels) {\n  long mergers = getTotalMergersInLevel(level);\n}","typeGuard":"boolean isValidLevel(int level, int totalMergingLevels) {\n  return level >= 0 && totalMergingLevels != SuperSorter.UNKNOWN_LEVEL && level < totalMergingLevels;\n}","tryCatchPattern":"try {\n  mergers = getTotalMergersInLevel(level);\n} catch (IllegalStateException e) {\n  if (e.getMessage() != null && e.getMessage().startsWith(\"Invalid level\")) {\n    mergers = SuperSorter.UNKNOWN_TOTAL; // treat as unknown rather than failing the query\n  } else {\n    throw e;\n  }\n}","preventionTips":["Always derive level indices from totalMergingLevels with strict < comparisons.","Treat UNKNOWN_LEVEL/UNKNOWN_TOTAL sentinels as unknown state, never as level values.","Set totalMergingLevels before scheduling any merges."],"tags":["internal-state","index-out-of-range","sorting"],"backgroundTag":"internal-invariant-violation","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"}