apache/pulsar · error · IllegalArgumentException

Keys and values must be >= 0

Error message

Keys and values must be >= 0

What it means

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.

Source

Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/util/collections/ConcurrentLongPairSet.java:681

        hash += 31 + (key2 * HashMixer);
        hash ^= hash >>> R;
        hash *= HashMixer;
        return hash;
    }

    static final int signSafeMod(long n, int max) {
        // as the ITEM_SIZE of Section is 2, so the index is the multiple of 2
        // that is to left shift 1 bit
        return (int) (n & (max - 1)) << 1;
    }

    private static int alignToPowerOfTwo(int n) {
        return (int) Math.pow(2, 32 - Integer.numberOfLeadingZeros(n - 1));
    }

    private static void checkBiggerEqualZero(long n) {
        if (n < 0L) {
            throw new IllegalArgumentException("Keys and values must be >= 0");
        }
    }

    /**
     * Class representing two long values.
     */
    public static class LongPair implements Comparable<LongPair> {
        public final long first;
        public final long second;

        public LongPair(long first, long second) {
            this.first = first;
            this.second = second;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof LongPair) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Validate both longs are >= 0 before calling the set API
  2. Replace -1/UNSET sentinels with a presence flag instead of inserting them
  3. Encode negative domain values into non-negative space before storing

Example fix

// before
set.add(ledgerId, entryId); // ledgerId may be -1 when unset
// after
if (ledgerId >= 0 && entryId >= 0) {
    set.add(ledgerId, entryId);
}
Defensive patterns

Strategy: validation

Validate before calling

static boolean canStore(long first, long second) {
    return first >= 0 && second >= 0;
}

Try / catch

try {
    set.add(a, b);
} catch (IllegalArgumentException e) {
    log.warn("Rejected negative pair in LongPairSet: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Calling add(x,y), contains(x,y), or remove(x,y) with x or y < 0.

Common situations: Adding ledger/entry ids or offsets that were computed with signed arithmetic and went negative (underflow, sentinel -1 leak).

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/8d9548ac853f08cd. Report an issue: GitHub.