apache/pulsar · error · IllegalArgumentException
Ranges for KeyShared policy with overlap between
Error message
Ranges for KeyShared policy with overlap between
What it means
KeySharedPolicy.KeySharedPolicySticky.validate() performs an O(n^2) pairwise check that no two sticky hash ranges intersect. If range1.intersect(range2) returns non-null for two distinct ranges, the same hash slots would be claimed by multiple consumers, so key-to-consumer assignment would be ambiguous. The policy is rejected with IllegalArgumentException naming both overlapping ranges.
Source
Thrown at pulsar-client-api/src/main/java/org/apache/pulsar/client/api/KeySharedPolicy.java:119
public KeySharedPolicySticky ranges(Range... ranges) {
this.ranges.addAll(Arrays.asList(ranges));
return this;
}
@Override
public void validate() {
if (ranges.isEmpty()) {
throw new IllegalArgumentException("Ranges for KeyShared policy must not be empty.");
}
for (int i = 0; i < ranges.size(); i++) {
Range range1 = ranges.get(i);
if (range1.getStart() < 0 || range1.getEnd() >= DEFAULT_HASH_RANGE_SIZE) {
throw new IllegalArgumentException("Ranges must be [0, 65535] but provided range is " + range1);
}
for (int j = 0; j < ranges.size(); j++) {
Range range2 = ranges.get(j);
if (i != j && range1.intersect(range2) != null) {
throw new IllegalArgumentException("Ranges for KeyShared policy with overlap between " + range1
+ " and " + range2);
}
}
}
}
public List<Range> getRanges() {
return ranges;
}
}
/**
* Auto split hash range key shared policy.
*/
public static class KeySharedPolicyAutoSplit extends KeySharedPolicy {
private static final long serialVersionUID = 1L;
KeySharedPolicyAutoSplit() {View on GitHub (pinned to 820761864e)
Solutions
- Adjust the ranges so every slot belongs to at most one range, e.g. Range.of(0, 100) and Range.of(101, 200).
- Generate ranges programmatically by partitioning 0..65534 into N equal non-overlapping slices instead of hardcoding boundaries.
- Sort ranges by start and assert range[i].end < range[i+1].start before calling stickyRanges.
Example fix
// before List<Range> ranges = Arrays.asList(Range.of(0, 100), Range.of(50, 200)); // after List<Range> ranges = Arrays.asList(Range.of(0, 100), Range.of(101, 200)); // no overlap
Defensive patterns
Strategy: validation
Validate before calling
static void checkNoOverlap(List<Range> ranges) {
List<Range> sorted = new ArrayList<>(ranges);
sorted.sort(Comparator.comparingInt(Range::getStart));
for (int i = 1; i < sorted.size(); i++) {
if (sorted.get(i).getStart() <= sorted.get(i - 1).getEnd())
throw new IllegalArgumentException("Overlap: " + sorted.get(i - 1) + " vs " + sorted.get(i));
}
}
checkNoOverlap(ranges); // before stickyRanges Type guard
static boolean isNonOverlapping(List<Range> ranges) {
for (int i = 0; i < ranges.size(); i++)
for (int j = i + 1; j < ranges.size(); j++)
if (ranges.get(i).intersect(ranges.get(j)) != null) return false;
return true;
} Try / catch
try {
KeySharedPolicy policy = KeySharedPolicy.stickyRanges(ranges);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Ranges for KeyShared policy with overlap")) {
// parse the two ranges from the message, split the shared boundary
} else throw e;
} Prevention
- Sort ranges by start and assert range[i].end < range[i+1].start before subscribing.
- Split the hash space with code (e.g. 65535 / N slices) rather than manual numbers.
- Keep per-consumer range lists in one shared config so assignments cannot drift apart.
When it happens
Trigger: Building KeySharedPolicy.stickyRanges(Arrays.asList(Range.of(0, 100), Range.of(50, 200))) — any two ranges whose [start, end] intervals share at least one slot (e.g. touching via a common index) when the consumer attaches.
Common situations: Programmatically splitting the hash space with rounding errors (ceil/floor producing duplicate boundary values); copy-pasting range lists across consumers and forgetting to shrink one; merging configs where two tenants were assigned overlapping slices.
Related errors
- Ranges must be [0, 65535] but provided range is
- Segments are not adjacent: ${hashRange1} and ${hashRange2}
- Positions must not be null
- Invalid range ${range}
- Split service unit should be split into 2 service units.
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/e831288f1dd6306f.
Report an issue: GitHub.