apache/druid · error · IllegalStateException
Unable to set %d total mergers for level %d. Level must be n
Error message
Unable to set %d total mergers for level %d. Level must be non-negative
What it means
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.
Source
Thrown at processing/src/main/java/org/apache/druid/frame/processor/SuperSorterProgressTracker.java:122
throw new ISE(
"Max level found in levelToTotalBatches is %d (0-indexed). Cannot set totalMergingLevels to %d",
max,
totalMergingLevels
);
}
});
this.totalMergingLevels = totalMergingLevels;
}
/**
* Sets the total mergers for a level. Can be set only once, except for the ultimate level (if total levels are known)
* because they get overridden by totalMergersForUltimateLevel
*/
public synchronized void setTotalMergersForLevel(final int level, final long totalMergers)
{
if (level < 0) {
throw new ISE("Unable to set %d total mergers for level %d. Level must be non-negative", totalMergers, level);
}
if (totalMergingLevels != SuperSorter.UNKNOWN_LEVEL && level >= totalMergingLevels) {
throw new ISE(
"Cannot set total mergers for level %d. Valid levels range from 0 to %d",
level,
totalMergingLevels - 1
);
}
if (totalMergingLevels != SuperSorter.UNKNOWN_LEVEL
&& level < totalMergingLevels - 1 // This condition is only present for levels excluding the ultimate level
&& levelToTotalBatches.containsKey(level)) {
throw new ISE("Total mergers are already present for the level %d", level);
}
levelToTotalBatches.put(level, totalMergers);
}
/**
* Sets the number of mergers in the ultimate level (number of mergers = number of output partitions).View on GitHub (pinned to 9b90983fd2)
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.
Example fix
// before
tracker.setTotalMergersForLevel(currentLevel - 1, mergers); // currentLevel == 0
// after
if (currentLevel > 0) {
tracker.setTotalMergersForLevel(currentLevel - 1, mergers);
} Defensive patterns
Strategy: validation
Validate before calling
if (level >= 0) {
tracker.setTotalMergersForLevel(level, mergers);
} Type guard
boolean isNonNegativeLevel(int level) { return level >= 0; } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid level %d
- Max level found in levelToMergedBatches is %d (0-indexed). C
- Max level found in levelToTotalBatches is %d (0-indexed). Ca
- Cannot set total mergers for level %d. Valid levels range fr
- Total mergers are already present for the level %d
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/72c05c823273d7f8.
Report an issue: GitHub.