{"record":{"id":"06adaddb23f5c1cb","repo":"apache/pulsar","slug":"messageidv5-missing-multi-topic-vector-was-the-m","errorCode":null,"errorMessage":"MessageIdV5 missing multi-topic vector — was the message delivered through a multi-topic stream consumer?","messagePattern":"MessageIdV5 missing multi-topic vector — was the message delivered through a multi-topic stream consumer\\?","errorType":"exception","errorClass":"java.lang.IllegalStateException","httpStatus":null,"severity":"error","filePath":"pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/MultiTopicStreamConsumer.java","lineNumber":334,"sourceCode":"    public void acknowledgeCumulative(MessageId messageId, Transaction txn) {\n        // Transactions on multi-topic are best-effort across per-topic consumers — each\n        // per-topic ack is independently transactional. See note in the design doc.\n        fanOutCumulativeAck(messageId, (sc, vector) -> sc.ackUpToVector(vector));\n    }\n\n    /**\n     * For a cumulative ack on a multi-topic message, look up its multi-topic vector\n     * and invoke the per-topic ack on every parent topic.\n     */\n    private void fanOutCumulativeAck(MessageId messageId,\n                                     java.util.function.BiConsumer<ScalableStreamConsumer<T>,\n                                             Map<Long, org.apache.pulsar.client.api.MessageId>> action) {\n        if (!(messageId instanceof MessageIdV5 id)) {\n            throw new IllegalArgumentException(\"Expected MessageIdV5, got: \" + messageId.getClass());\n        }\n        Map<String, Map<Long, org.apache.pulsar.client.api.MessageId>> vector = id.multiTopicVector();\n        if (vector == null) {\n            throw new IllegalStateException(\"MessageIdV5 missing multi-topic vector — was the\"\n                    + \" message delivered through a multi-topic stream consumer?\");\n        }\n        for (var entry : vector.entrySet()) {\n            PerTopic<T> state = perTopic.get(entry.getKey());\n            if (state == null) {\n                // Topic left the matching set since this message was enqueued: we've\n                // detached it and no longer ack removed topics, so skip its slice.\n                continue;\n            }\n            action.accept(state.consumer, entry.getValue());\n        }\n    }\n\n    @Override\n    public AsyncStreamConsumer<T> async() {\n        return asyncView;\n    }\n","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/MultiTopicStreamConsumer.java#L316-L352","documentation":"Thrown by MultiTopicStreamConsumer.fanOutCumulativeAck when the MessageIdV5 lacks its multiTopicVector(). Without the per-topic id map, the consumer cannot route the cumulative ack across the topic set, so it fails with IllegalStateException.","triggerScenarios":"Calling acknowledgeCumulative with a MessageIdV5 not produced by multi-topic stream delivery — single-topic v5 id, deserialized id missing vector metadata, or hand-constructed id.","commonSituations":"Persisting and later replaying ids without the multi-topic vector; acking across consumer instances; client version migration dropping metadata.","solutions":["Ack with ids delivered by this exact consumer instance","Verify id.multiTopicVector() != null before calling acknowledgeCumulative","When persisting ids, serialize the full multi-topic metadata"],"exampleFix":"// before\nstreamConsumer.acknowledgeCumulative(id); // vector-less id\n// after\nif (id instanceof MessageIdV5 v5 && v5.multiTopicVector() != null) {\n    streamConsumer.acknowledgeCumulative(v5);\n}","handlingStrategy":"type-guard","validationCode":"if (id instanceof MessageIdV5 v5 && v5.multiTopicVector() == null) { handleVectorless(); }","typeGuard":"static boolean hasMultiTopicVector(MessageId id) { return id instanceof MessageIdV5 v5 && v5.multiTopicVector() != null; }","tryCatchPattern":"try { consumer.acknowledgeCumulative(id); } catch (IllegalStateException e) { log.warn(\"missing multi-topic vector\", e); }","preventionTips":["Serialize full multi-topic metadata when persisting ids","Ack only with ids from multi-topic stream delivery"],"tags":["pulsar","client","ack","multi-topic","missing-metadata"],"backgroundTag":"message-id-missing-topic-metadata","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"}