{"record":{"id":"f63675ad4894af39","repo":"apache/pulsar","slug":"ranges-for-keyshared-policy-must-not-be-empty","errorCode":null,"errorMessage":"Ranges for KeyShared policy must not be empty.","messagePattern":"Ranges for KeyShared policy must not be empty\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-client-api/src/main/java/org/apache/pulsar/client/api/KeySharedPolicy.java","lineNumber":109,"sourceCode":"        KeySharedPolicySticky() {\n            this.keySharedMode = KeySharedMode.STICKY;\n            this.ranges = new ArrayList<>();\n        }\n\n        public KeySharedPolicySticky ranges(List<Range> ranges) {\n            this.ranges.addAll(ranges);\n            return this;\n        }\n\n        public KeySharedPolicySticky ranges(Range... ranges) {\n            this.ranges.addAll(Arrays.asList(ranges));\n            return this;\n        }\n\n        @Override\n        public void validate() {\n            if (ranges.isEmpty()) {\n                throw new IllegalArgumentException(\"Ranges for KeyShared policy must not be empty.\");\n            }\n            for (int i = 0; i < ranges.size(); i++) {\n                Range range1 = ranges.get(i);\n                if (range1.getStart() < 0 || range1.getEnd() >= DEFAULT_HASH_RANGE_SIZE) {\n                    throw new IllegalArgumentException(\"Ranges must be [0, 65535] but provided range is \" + range1);\n                }\n                for (int j = 0; j < ranges.size(); j++) {\n                    Range range2 = ranges.get(j);\n                    if (i != j && range1.intersect(range2) != null) {\n                        throw new IllegalArgumentException(\"Ranges for KeyShared policy with overlap between \" + range1\n                                + \" and \" + range2);\n                    }\n                }\n            }\n        }\n\n        public List<Range> getRanges() {\n            return ranges;","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-api/src/main/java/org/apache/pulsar/client/api/KeySharedPolicy.java#L91-L127","documentation":"KeySharedPolicy.KeySharedPolicySticky.validate() rejects a sticky ranges policy whose list of hash ranges is empty, throwing IllegalArgumentException. A sticky KeyShared consumer must partition the 0-65535 hash space into at least one non-empty range; an empty list would leave the consumer unable to receive any messages.","triggerScenarios":"ConsumerBuilder.keySharedPolicy(KeySharedPolicy.stickyRanges().ranges(new ArrayList<>())) or an empty Range list passed to ranges(...), then subscribe()/validate runs. Also fired when the list itself is empty even if individual ranges would be valid.","commonSituations":"Computing ranges programmatically (e.g. splitting the hash space across N consumers) when N is 0 or the split logic returns nothing; copying example code but clearing the ranges list; building the policy from empty configuration.","solutions":["Provide at least one Range, e.g. Range.of(0, 65535) to cover the full hash space.","Fix range-splitting code so it always yields non-empty ranges for all consumers.","Catch IllegalArgumentException and fall back to KeySharedPolicy.autoSplitHashRange() when no ranges are configured.","Ensure each range is within [0, 65535] to avoid the related out-of-range error."],"exampleFix":"// before\nKeySharedPolicy policy = KeySharedPolicy.stickyRanges()\n    .ranges(Collections.emptyList());\n// after\nKeySharedPolicy policy = KeySharedPolicy.stickyRanges()\n    .ranges(Collections.singletonList(Range.of(0, 65535)));","handlingStrategy":"validation","validationCode":"List<Range> ranges = /* computed ranges */;\nif (ranges == null || ranges.isEmpty()) {\n    ranges = Collections.singletonList(Range.of(0, 65535));\n}\nranges.forEach(r -> {\n    if (r.getStart() < 0 || r.getEnd() >= 65536) {\n        throw new IllegalArgumentException(\"Range out of [0,65535]: \" + r);\n    }\n});\nKeySharedPolicy policy = KeySharedPolicy.stickyRanges().ranges(ranges);","typeGuard":null,"tryCatchPattern":"try {\n    consumerBuilder.keySharedPolicy(stickyPolicy);\n} catch (IllegalArgumentException e) {\n    log.warn(\"Invalid sticky ranges, falling back to auto split: {}\", e.getMessage());\n    consumerBuilder.keySharedPolicy(KeySharedPolicy.autoSplitHashRange());\n}","preventionTips":["Cover the full 0-65535 hash space with your ranges and never leave the list empty.","Guard range-splitting code against producing zero ranges (e.g. when splitting across 0 consumers).","Fall back to KeySharedPolicy.autoSplitHashRange() when sticky ranges cannot be computed."],"tags":["pulsar","consumer","keyshare","validation"],"backgroundTag":"invalid-policy-configuration","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}