{"record":{"id":"8d9548ac853f08cd","repo":"apache/pulsar","slug":"keys-and-values-must-be-0-8d9548","errorCode":null,"errorMessage":"Keys and values must be >= 0","messagePattern":"Keys and values must be >= 0","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/ConcurrentLongPairSet.java","lineNumber":681,"sourceCode":"        hash += 31 + (key2 * HashMixer);\n        hash ^= hash >>> R;\n        hash *= HashMixer;\n        return hash;\n    }\n\n    static final int signSafeMod(long n, int max) {\n        // as the ITEM_SIZE of Section is 2, so the index is the multiple of 2\n        // that is to left shift 1 bit\n        return (int) (n & (max - 1)) << 1;\n    }\n\n    private static int alignToPowerOfTwo(int n) {\n        return (int) Math.pow(2, 32 - Integer.numberOfLeadingZeros(n - 1));\n    }\n\n    private static void checkBiggerEqualZero(long n) {\n        if (n < 0L) {\n            throw new IllegalArgumentException(\"Keys and values must be >= 0\");\n        }\n    }\n\n    /**\n     * Class representing two long values.\n     */\n    public static class LongPair implements Comparable<LongPair> {\n        public final long first;\n        public final long second;\n\n        public LongPair(long first, long second) {\n            this.first = first;\n            this.second = second;\n        }\n\n        @Override\n        public boolean equals(Object obj) {\n            if (obj instanceof LongPair) {","sourceCodeStart":663,"sourceCodeEnd":699,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/ConcurrentLongPairSet.java#L663-L699","documentation":"ConcurrentLongPairSet stores pairs of non-negative longs; checkBiggerEqualZero throws IllegalArgumentException when any member of a pair passed to add/contains/remove is negative. The set is intentionally restricted to non-negative values.","triggerScenarios":"Calling add(x,y), contains(x,y), or remove(x,y) with x or y < 0.","commonSituations":"Adding ledger/entry ids or offsets that were computed with signed arithmetic and went negative (underflow, sentinel -1 leak).","solutions":["Validate both longs are >= 0 before calling the set API","Replace -1/UNSET sentinels with a presence flag instead of inserting them","Encode negative domain values into non-negative space before storing"],"exampleFix":"// before\nset.add(ledgerId, entryId); // ledgerId may be -1 when unset\n// after\nif (ledgerId >= 0 && entryId >= 0) {\n    set.add(ledgerId, entryId);\n}","handlingStrategy":"validation","validationCode":"static boolean canStore(long first, long second) {\n    return first >= 0 && second >= 0;\n}","typeGuard":null,"tryCatchPattern":"try {\n    set.add(a, b);\n} catch (IllegalArgumentException e) {\n    log.warn(\"Rejected negative pair in LongPairSet: {}\", e.getMessage());\n}","preventionTips":["Clamp or reject negative values upstream of the set","Replace sentinel -1 with explicit presence flags","Unit-test boundary values near overflow/underflow"],"tags":["java","illegal-argument","precondition"],"backgroundTag":"negative-key-not-allowed","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"}