{"record":{"id":"3188b20ddacd0580","repo":"apache/pulsar","slug":"expected-multimessageidimpl-object-got-instance-o","errorCode":null,"errorMessage":"expected MultiMessageIdImpl object. Got instance of ","messagePattern":"expected MultiMessageIdImpl object\\. Got instance of ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"warning","filePath":"pulsar-client/src/main/java/org/apache/pulsar/client/impl/MultiMessageIdImpl.java","lineNumber":57,"sourceCode":"    }\n\n    // TODO: Add support for Serialization and Deserialization\n    //  https://github.com/apache/pulsar/issues/4940\n    @Override\n    public byte[] toByteArray() {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(map);\n    }\n\n    // If all messageId in map are same size, and all bigger/smaller than the other, return valid value.\n    @Override\n    public int compareTo(MessageId o) {\n        if (!(o instanceof MultiMessageIdImpl)) {\n            throw new IllegalArgumentException(\n                \"expected MultiMessageIdImpl object. Got instance of \" + o.getClass().getName());\n        }\n\n        MultiMessageIdImpl other = (MultiMessageIdImpl) o;\n        Map<String, MessageId> otherMap = other.getMap();\n\n        if ((map == null || map.isEmpty()) && (otherMap == null || otherMap.isEmpty())) {\n            return 0;\n        }\n\n        if (otherMap == null || map == null || otherMap.size() != map.size()) {\n            throw new IllegalArgumentException(\"Current size and other size not equals\");\n        }\n\n        int result = 0;\n        for (Entry<String, MessageId> entry : map.entrySet()) {\n            MessageId otherMessage = otherMap.get(entry.getKey());\n            if (otherMessage == null) {","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client/src/main/java/org/apache/pulsar/client/impl/MultiMessageIdImpl.java#L39-L75","documentation":"MultiMessageIdImpl.compareTo only knows how to compare against another MultiMessageIdImpl. Passing any other MessageId implementation (MessageIdImpl, BatchMessageIdImpl, TopicMessageIdImpl, etc.) throws IllegalArgumentException naming the offending class. Comparison across the single-partition and multi-partition id types is undefined in this class.","triggerScenarios":"Calling compareTo (directly or via equals/sorting) between a MultiMessageIdImpl and any non-MultiMessageIdImpl MessageId — e.g. comparing a partitioned-topic cursor to a message id from a single-partition consumer.","commonSituations":"Generic MessageId comparison/sorting code that mixes ids from partitioned and non-partitioned consumers; test utilities (testMultiMessageIdCompareto) passing the wrong type; mapping TopicMessageIdImpl results back without unwrapping.","solutions":["Only compare MultiMessageIdImpl with MultiMessageIdImpl; unwrap TopicMessageIdImpl via getInnerMessageId() to compare at the partition level","If you need cross-type comparison, convert the single id into a map keyed by topic and build a MultiMessageIdImpl, or compare ledgerId/entryId explicitly","Guard with instanceof before calling compareTo","Catch IllegalArgumentException around compareTo when ids come from mixed sources"],"exampleFix":"// before\nint r = multiId.compareTo(singleId); // IllegalArgumentException\n// after\nif (multiId instanceof MultiMessageIdImpl && singleId instanceof MultiMessageIdImpl) {\n    int r = multiId.compareTo(singleId);\n} else {\n    // compare per-topic inner ids instead\n    MessageId inner = ((TopicMessageIdImpl) singleId).getInnerMessageId();\n    ...\n}","handlingStrategy":"type-guard","validationCode":"Integer compareSafely(MessageId a, MessageId b) {\n    if (a instanceof MultiMessageIdImpl && b instanceof MultiMessageIdImpl) return a.compareTo(b);\n    return null; // cross-type comparison unsupported\n}","typeGuard":"boolean comparableMultiIds(MessageId a, MessageId b) {\n    return a instanceof MultiMessageIdImpl && b instanceof MultiMessageIdImpl;\n}","tryCatchPattern":"try {\n    int r = a.compareTo(b);\n} catch (IllegalArgumentException e) {\n    // unwrap TopicMessageIdImpl / compare per-topic inner ids instead\n}","preventionTips":["Only compare ids of the same concrete MessageId type","Unwrap TopicMessageIdImpl.getInnerMessageId() before low-level comparisons","Avoid generic MessageId comparators/sorters that mix partitioned and non-partitioned ids"],"tags":["pulsar","messageid","compareto","illegal-argument","partitioned"],"backgroundTag":"incompatible-messageid-comparison","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"}