apache/pulsar · error · java.lang.IllegalArgumentException
Entry-bucket 0 must span at least [0,1] to hold the canonica
Error message
Entry-bucket 0 must span at least [0,1] to hold the canonical hash
What it means
Entry hashes are normalized to per-bucket canonical values, and bucket 0's canonical hash is 1. If the first declared range ends below 1 (i.e. bucket 0 is just [0,0]), the canonical hash 1 falls outside every bucket, breaking routing and the draining/handoff machinery. validateBucketBoundaries therefore requires ranges.get(0).getEnd() >= 1.
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentEntryBucketDispatcherMultipleConsumers.java:101
}
List<Range> ranges = new ArrayList<>(count);
int expectedStart = 0;
for (int i = 0; i < count; i++) {
IntRange r = ksm.getHashRangeAt(i);
if (r.getStart() != expectedStart || r.getEnd() < r.getStart()) {
throw new IllegalArgumentException("Entry-bucket boundaries must be ascending, "
+ "contiguous and start at 0: found [" + r.getStart() + "," + r.getEnd()
+ "] where start " + expectedStart + " was expected");
}
ranges.add(Range.of(r.getStart(), r.getEnd()));
expectedStart = r.getEnd() + 1;
}
if (expectedStart != EntryBucketConsumerSelector.DEFAULT_RANGE_SIZE) {
throw new IllegalArgumentException("Entry-bucket boundaries must tile the 16-bit ring: "
+ "last range ends at " + (expectedStart - 1));
}
if (ranges.get(0).getEnd() < 1) {
throw new IllegalArgumentException(
"Entry-bucket 0 must span at least [0,1] to hold the canonical hash");
}
return ranges;
}
@Override
public synchronized CompletableFuture<Void> addConsumer(Consumer consumer) {
// A segment's bucketing is immutable, so every consumer must declare the boundaries the
// dispatcher was created with — a mismatch is a client bug or a stale layout, not a race.
try {
List<Range> declared = validateBucketBoundaries(consumer.getKeySharedMeta());
if (!declared.equals(bucketSelector.getBucketRanges())) {
return CompletableFuture.failedFuture(new BrokerServiceException.ConsumerAssignException(
"Consumer declares different entry-bucket boundaries than the subscription: "
+ declared + " != " + bucketSelector.getBucketRanges()));
}
} catch (IllegalArgumentException e) {
return CompletableFuture.failedFuture(View on GitHub (pinned to 820761864e)
Solutions
- Widen the first range to at least [0,1] (end >= 1) and merge the following segment accordingly, keeping overall contiguity and full ring coverage.
- Adjust the boundary generator so the first segment always spans at least two hash values.
- If you need 65536 single-hash buckets, use the regular Key_Shared hashing path instead of entry-bucket dispatch — entry-bucket segmentation assumes coarser buckets.
Example fix
// before ksm.addHashRange().setStart(0).setEnd(0); // bucket 0 can't hold canonical hash 1 ksm.addHashRange().setStart(1).setEnd(21844); ... // after ksm.addHashRange().setStart(0).setEnd(1); // spans at least [0,1] ksm.addHashRange().setStart(2).setEnd(21844); ...
Defensive patterns
Strategy: validation
Validate before calling
static void assertFirstBucketHoldsCanonicalHash(KeySharedMeta ksm) {
if (ksm.getHashRangesCount() == 0 || ksm.getHashRangeAt(0).getEnd() < 1) {
throw new IllegalArgumentException(
"first bucket range must end at >= 1 (canonical hash 1)");
}
} Type guard
static boolean firstBucketSpansCanonicalHash(KeySharedMeta ksm) {
return ksm.getHashRangesCount() > 0 && ksm.getHashRangeAt(0).getEnd() >= 1;
} Prevention
- Never generate width-1 first buckets; enforce a minimum first-range width of 2.
- Avoid 65536 single-hash segments — entry-bucket dispatch targets coarse segments.
- Include firstRange.end >= 1 in the boundary generator's self-check.
When it happens
Trigger: A boundary list whose first range is exactly [0,0] — typically when a very large number of fine-grained segments each get width 1, or when a generator emits [0,0] as the first single-value bucket.
Common situations: Generating one range per hash value (65536 ranges of width 1), which puts the canonical hash 1 in bucket 1's range and leaves bucket 0 unable to hold its canonical value; scripted boundary generation that doesn't special-case the first segment.
Related errors
- Entry-bucket boundaries must be ascending, contiguous and st
- Entry-bucket boundaries must tile the 16-bit ring: last rang
- Entry-bucket subscription must declare the segment's bucket
- entryFilterNames can't be empty. To remove entry filters use
- The offloadPolicies must be specified for namespace offload.
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/0593f70a5253cea6.
Report an issue: GitHub.