{"record":{"id":"1a3b5d2131798716","repo":"apache/pulsar","slug":"messageidv5-missing-parent-topic-was-the-message","errorCode":null,"errorMessage":"MessageIdV5 missing parent topic — was the message delivered through a multi-topic consumer?","messagePattern":"MessageIdV5 missing parent topic — was the message delivered through a multi-topic consumer\\?","errorType":"exception","errorClass":"java.lang.IllegalStateException","httpStatus":null,"severity":"error","filePath":"pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/MultiTopicQueueConsumer.java","lineNumber":335,"sourceCode":"\n    @Override\n    public void acknowledge(MessageId messageId, Transaction txn) {\n        routeAck(messageId, ptc -> ptc.acknowledge(messageId, txn));\n    }\n\n    @Override\n    public void negativeAcknowledge(MessageId messageId) {\n        routeAck(messageId, ptc -> ptc.negativeAcknowledge(messageId));\n    }\n\n    /** Look up the per-topic consumer via the parent topic tag and delegate. */\n    private void routeAck(MessageId messageId, java.util.function.Consumer<QueueConsumer<T>> action) {\n        if (!(messageId instanceof MessageIdV5 id)) {\n            throw new IllegalArgumentException(\"Expected MessageIdV5, got: \" + messageId.getClass());\n        }\n        String parent = id.parentTopic();\n        if (parent == null) {\n            throw new IllegalStateException(\"MessageIdV5 missing parent topic — was the message\"\n                    + \" delivered through a multi-topic consumer?\");\n        }\n        PerTopicState<T> state = perTopic.get(parent);\n        if (state == null) {\n            // Topic was removed between deliver and ack. Fine — broker has dropped the\n            // session for that topic. Drop the ack silently.\n            log.debug().attr(\"topic\", parent)\n                    .log(\"Ack for removed topic; dropping\");\n            return;\n        }\n        action.accept(state.consumer);\n    }\n\n    @Override\n    public AsyncQueueConsumer<T> async() {\n        return asyncView;\n    }\n","sourceCodeStart":317,"sourceCodeEnd":353,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/MultiTopicQueueConsumer.java#L317-L353","documentation":"Thrown by MultiTopicQueueConsumer.routeAck when the MessageIdV5 is valid but its parentTopic() is null. A multi-topic ack needs to know which underlying topic the message came from; a null parent topic means the id was not produced by this multi-topic consumer's delivery path.","triggerScenarios":"Calling acknowledge/negativeAcknowledge with a MessageIdV5 that was created outside multi-topic delivery — e.g. from a single-topic MessageIdV5 consumer, manually constructed, or deserialized without topic metadata.","commonSituations":"Ids shared across consumer instances; ids deserialized from a database/journal where parent-topic metadata was stripped; acking a message received by a different consumer.","solutions":["Ack messages with the same consumer instance that delivered them","Verify the MessageIdV5 was created by multi-topic delivery (parentTopic() != null) before acking","If persisting ids, store the parent topic alongside and reconstruct a valid id"],"exampleFix":"// before\notherConsumer.acknowledge(messageId); // id has no parent topic\n// after\nif (messageId instanceof MessageIdV5 id && id.parentTopic() != null) {\n    multiTopicConsumer.acknowledge(id);\n}","handlingStrategy":"type-guard","validationCode":"if (id instanceof MessageIdV5 v5 && v5.parentTopic() == null) { handleOrphan(); }","typeGuard":"static boolean hasParentTopic(MessageId id) { return id instanceof MessageIdV5 v5 && v5.parentTopic() != null; }","tryCatchPattern":"try { consumer.acknowledge(id); } catch (IllegalStateException e) { log.warn(\"id not from multi-topic delivery\", e); }","preventionTips":["Ack with the delivering consumer only","Persist parent-topic metadata alongside stored ids"],"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-14T00:17:10.932Z"}