apache/pulsar · warning · IllegalArgumentException

Different MessageId in Map get different compare result

Error message

Different MessageId in Map get different compare result

What it means

MultiMessageIdImpl.compareTo demands a consistent total ordering: every per-topic comparison must yield the same sign (all greater, all equal, or all smaller). If per-partition comparisons disagree (some topics ahead, some behind), no valid ordering exists and it throws IllegalArgumentException('Different MessageId in Map get different compare result'). The class documents itself as only returning a value when all ids are uniformly bigger/smaller.

Source

Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/MultiMessageIdImpl.java:86

        if (otherMap == null || map == null || otherMap.size() != map.size()) {
            throw new IllegalArgumentException("Current size and other size not equals");
        }

        int result = 0;
        for (Entry<String, MessageId> entry : map.entrySet()) {
            MessageId otherMessage = otherMap.get(entry.getKey());
            if (otherMessage == null) {
                throw new IllegalArgumentException(
                    "Other MessageId not have topic " + entry.getKey());
            }

            int currentResult = entry.getValue().compareTo(otherMessage);
            if (result == 0) {
                result = currentResult;
            } else if (currentResult == 0) {
                continue;
            } else if (result != currentResult) {
                throw new IllegalArgumentException(
                    "Different MessageId in Map get different compare result");
            } else {
                continue;
            }
        }

        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof MultiMessageIdImpl) {
            MultiMessageIdImpl other = (MultiMessageIdImpl) obj;

            try {
                return compareTo(other) == 0;
            } catch (IllegalArgumentException e) {
                return false;

View on GitHub (pinned to 820761864e)

Solutions

  1. Don't compare multi-partition cursors with compareTo for ordering decisions; instead compare per-partition MessageIdImpl individually and define your own policy (e.g. min/max per topic)
  2. If you need 'has this cursor reached X', check per-partition containment (every partition's id >= target for that partition) rather than compareTo
  3. Store per-partition cursors and compare each independently on resume
  4. Catch IllegalArgumentException and fall back to per-partition comparison

Example fix

// before
boolean ahead = myCursor.compareTo(otherCursor) > 0; // often throws on skewed progress
// after
boolean ahead = true;
for (Map.Entry<String, MessageId> e : myCursor.getMap().entrySet()) {
    MessageId otherId = otherCursor.getMap().get(e.getKey());
    if (e.getValue().compareTo(otherId) < 0) { ahead = false; break; }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// per-partition skew check before compareTo
boolean uniformlyOrdered(MultiMessageIdImpl a, MultiMessageIdImpl b, int sign) {
    return a.getMap().entrySet().stream()
        .allMatch(e -> sign * e.getValue().compareTo(b.getMap().get(e.getKey())) >= 0);
}

Type guard

boolean hasConsistentOrder(MultiMessageIdImpl a, MultiMessageIdImpl b) {
    // true only if every per-topic comparison has the same sign
    return uniformlyOrdered(a, b, 1) || uniformlyOrdered(a, b, -1);
}

Try / catch

try {
    int r = a.compareTo(b);
} catch (IllegalArgumentException e) {
    // skewed progress: fall back to per-partition comparison with your own policy (min/max)
}

Prevention

When it happens

Trigger: Comparing two multi-partition cursors where the partitions have advanced unevenly — e.g. one consumer is ahead on partition 0 but behind on partition 1. This is the normal state for independent partitions, so direct compareTo between arbitrary cursors frequently hits this.

Common situations: Checkpoint/resume logic assuming a total order over partitioned cursors; comparing live cursors of two consumers on a partitioned topic with skewed consumption; sorting a list of multi-partition message ids.

Related errors


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