{"record":{"id":"0eb63a7c822bd130","repo":"apache/pulsar","slug":"range-end-must-range-start","errorCode":null,"errorMessage":"Range end must >= range start.","messagePattern":"Range end must >= range start\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-client-api/src/main/java/org/apache/pulsar/client/api/Range.java","lineNumber":40,"sourceCode":"import java.util.Objects;\nimport org.apache.pulsar.common.classification.InterfaceAudience;\nimport org.apache.pulsar.common.classification.InterfaceStability;\n\n/**\n * Int range.\n */\n@InterfaceAudience.Public\n@InterfaceStability.Stable\npublic class Range implements Comparable<Range>, Serializable {\n    private static final long serialVersionUID = 1L;\n\n    private final int start;\n    private final int end;\n\n\n    public Range(int start, int end) {\n        if (end < start) {\n            throw new IllegalArgumentException(\"Range end must >= range start.\");\n        }\n        this.start = start;\n        this.end = end;\n    }\n\n    public static Range of(int start, int end) {\n        return new Range(start, end);\n    }\n\n    public int getStart() {\n        return start;\n    }\n\n    public int getEnd() {\n        return end;\n    }\n\n    public Range intersect(Range range) {","sourceCodeStart":22,"sourceCodeEnd":58,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-api/src/main/java/org/apache/pulsar/client/api/Range.java#L22-L58","documentation":"The Range constructor validates that end >= start and throws IllegalArgumentException otherwise. A Range with an inverted interval is meaningless in Pulsar's hash-space model (used for KeyShared sticky ranges), so the constructor refuses to create such an object rather than propagating a broken invariant to downstream intersection/containment logic.","triggerScenarios":"Calling new Range(100, 50) or Range.of(100, 50) directly — any construction where the end is strictly less than the start.","commonSituations":"Swapped arguments when computing range boundaries from variables (Range.of(end, start)); computing start/end from user input or config where the ordering was never normalized; splitting logic that emits (high, low) by mistake.","solutions":["Swap the arguments so the smaller value is the start: Range.of(Math.min(a, b), Math.max(a, b)).","Normalize inputs before constructing: reject or clamp inverted intervals in your own config-loading code.","If a range legitimately became empty, model it explicitly (skip it) rather than constructing an inverted Range."],"exampleFix":"// before\nRange range = Range.of(end, start);\n// after\nRange range = Range.of(Math.min(start, end), Math.max(start, end));","handlingStrategy":"validation","validationCode":"static Range safeRange(int a, int b) {\n    if (b < a) throw new IllegalArgumentException(\"end < start: \" + a + \", \" + b);\n    return Range.of(a, b);\n}","typeGuard":"static boolean isValidInterval(int start, int end) {\n    return end >= start;\n}","tryCatchPattern":"try {\n    Range r = Range.of(start, end);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"Range end must >= range start\")) {\n        Range r = Range.of(Math.min(start, end), Math.max(start, end)); // normalize\n    } else throw e;\n}","preventionTips":["Normalize with Math.min/Math.max at every construction site fed by variables.","Validate config-loaded boundaries before they reach Range.of.","Keep start/end as adjacent parameters in named factory methods to avoid argument swaps."],"tags":["range","illegal-argument","validation"],"backgroundTag":"invalid-range-bounds","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}