{"record":{"id":"72c05c823273d7f8","repo":"apache/druid","slug":"unable-to-set-d-total-mergers-for-level-d-level","errorCode":null,"errorMessage":"Unable to set %d total mergers for level %d. Level must be non-negative","messagePattern":"Unable to set (.+?) total mergers for level (.+?)\\. Level must be non-negative","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/frame/processor/SuperSorterProgressTracker.java","lineNumber":122,"sourceCode":"        throw new ISE(\n            \"Max level found in levelToTotalBatches is %d (0-indexed). Cannot set totalMergingLevels to %d\",\n            max,\n            totalMergingLevels\n        );\n      }\n    });\n\n    this.totalMergingLevels = totalMergingLevels;\n  }\n\n  /**\n   * Sets the total mergers for a level. Can be set only once, except for the ultimate level (if total levels are known)\n   * because they get overridden by totalMergersForUltimateLevel\n   */\n  public synchronized void setTotalMergersForLevel(final int level, final long totalMergers)\n  {\n    if (level < 0) {\n      throw new ISE(\"Unable to set %d total mergers for level %d. Level must be non-negative\", totalMergers, level);\n    }\n    if (totalMergingLevels != SuperSorter.UNKNOWN_LEVEL && level >= totalMergingLevels) {\n      throw new ISE(\n          \"Cannot set total mergers for level %d. Valid levels range from 0 to %d\",\n          level,\n          totalMergingLevels - 1\n      );\n    }\n    if (totalMergingLevels != SuperSorter.UNKNOWN_LEVEL\n        && level < totalMergingLevels - 1 // This condition is only present for levels excluding the ultimate level\n        && levelToTotalBatches.containsKey(level)) {\n      throw new ISE(\"Total mergers are already present for the level %d\", level);\n    }\n    levelToTotalBatches.put(level, totalMergers);\n  }\n\n  /**\n   * Sets the number of mergers in the ultimate level (number of mergers = number of output partitions).","sourceCodeStart":104,"sourceCodeEnd":140,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/frame/processor/SuperSorterProgressTracker.java#L104-L140","documentation":"SuperSorterProgressTracker.setTotalMergersForLevel rejects negative level indices with this IllegalStateException. Levels are 0-indexed in the merge hierarchy, so a negative value is always a caller bug in the level arithmetic. The message includes both the totalMergers and the offending level for diagnosis.","triggerScenarios":"Calling setTotalMergersForLevel with a level computed as level-1 at level 0, or from a subtraction/index arithmetic that underflows; also passing an uninitialized/sentinel negative value for level.","commonSituations":"Custom merge drivers computing levels via integer arithmetic that goes one below zero; refactors renaming levels from 1-indexed to 0-indexed convention leaving stray -1 values.","solutions":["Clamp or validate the level parameter at the call site before invoking setTotalMergersForLevel (require level >= 0).","Check level arithmetic in the merge scheduler for underflow, especially first-iteration cases like level = currentLevel - 1.","Verify that all level constants use the 0-indexed convention consistently after any refactor.","Log the computed level and its derivation when it is negative to pinpoint the miscomputing caller."],"exampleFix":"// before\ntracker.setTotalMergersForLevel(currentLevel - 1, mergers); // currentLevel == 0\n// after\nif (currentLevel > 0) {\n  tracker.setTotalMergersForLevel(currentLevel - 1, mergers);\n}","handlingStrategy":"validation","validationCode":"if (level >= 0) {\n  tracker.setTotalMergersForLevel(level, mergers);\n}","typeGuard":"boolean isNonNegativeLevel(int level) { return level >= 0; }","tryCatchPattern":null,"preventionTips":["Validate computed levels at call sites, especially first-iteration arithmetic like currentLevel - 1.","Keep the 0-indexed level convention consistent across the merge driver.","Log negative levels with their derivation to catch miscomputations."],"tags":["internal-state","argument-validation","sorting"],"backgroundTag":"argument-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"}