{"record":{"id":"174b5e1bf49fbf53","repo":"apache/pulsar","slug":"cannot-handle-message-with-null-messageid","errorCode":null,"errorMessage":"Cannot handle message with null messageId","messagePattern":"Cannot handle message with null messageId","errorType":"exception","errorClass":"PulsarClientException.InvalidMessageException","httpStatus":null,"severity":"error","filePath":"pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java","lineNumber":428,"sourceCode":"                opBatchReceive.future.completeExceptionally(\n                        new PulsarClientException.AlreadyClosedException(\n                                String.format(\"The consumer which subscribes the topic %s with subscription name %s was\"\n                                                + \" already closed when cleaning and closing the consumers\",\n                                        topic, subscription)));\n            }\n        }\n    }\n\n    protected abstract Messages<T> internalBatchReceive() throws PulsarClientException;\n\n    protected abstract CompletableFuture<Messages<T>> internalBatchReceiveAsync();\n\n    private static void validateMessageId(Message<?> message) throws PulsarClientException {\n        if (message == null) {\n            throw new PulsarClientException.InvalidMessageException(\"Non-null message is required\");\n        }\n        if (message.getMessageId() == null) {\n            throw new PulsarClientException.InvalidMessageException(\"Cannot handle message with null messageId\");\n        }\n    }\n\n    private static void validateMessageId(MessageId messageId) throws PulsarClientException {\n        if (messageId == null) {\n            throw new PulsarClientException.InvalidMessageException(\"Cannot handle message with null messageId\");\n        }\n    }\n\n    private static void validateMessageIds(List<MessageId> messageIdList) throws PulsarClientException {\n        if (messageIdList == null) {\n            throw new PulsarClientException.InvalidMessageException(\"Cannot handle messages with null messageIdList\");\n        }\n        for (MessageId messageId : messageIdList) {\n            validateMessageId(messageId);\n        }\n    }\n","sourceCodeStart":410,"sourceCodeEnd":446,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java#L410-L446","documentation":"validateMessageId(Message) also verifies that the message carries a non-null MessageId; a message without an ID cannot be acknowledged or negatively acknowledged because the broker identifies messages by MessageId. Throws InvalidMessageException 'Cannot handle message with null messageId'. In practice this indicates a synthetic or deserialized Message whose ID was never populated.","triggerScenarios":"Calling acknowledge/acknowledgeAsync/acknowledgeCumulative/reconsumeLater*/validateMessages with a Message whose getMessageId() returns null — e.g., a hand-constructed MessageImpl, a mock in tests, or a message deserialized without its ID field.","commonSituations":"Unit-test mocks returning messages without IDs; wrapping/re-creating Message objects before ack; custom interceptors that strip or rebuild messages.","solutions":["Only acknowledge messages received from the consumer (they always carry an ID)","If constructing messages for tests, set a valid MessageId (e.g., new MessageIdImpl(ledgerId, entryId, partitionIndex))","Null-check message.getMessageId() before ack in defensive code paths"],"exampleFix":"// before\nMessage<String> fake = new MessageImpl<>();\nconsumer.acknowledge(fake); // messageId == null\n// after\nMessageId mid = new MessageIdImpl(ledgerId, entryId, partition);\nconsumer.acknowledge(mid); // ack by MessageId directly","handlingStrategy":"validation","validationCode":"if (message == null || message.getMessageId() == null) {\n    throw new IllegalArgumentException(\"Message or messageId is null; cannot ack\");\n}","typeGuard":"boolean hasMessageId(Message<?> m) {\n    return m != null && m.getMessageId() != null;\n}","tryCatchPattern":"try {\n    consumer.acknowledge(message);\n} catch (PulsarClientException.InvalidMessageException e) {\n    log.warn(\"Message has no messageId; skipping ack\");\n}","preventionTips":["Never construct synthetic Message objects for ack — ack by MessageId instead","In tests, use real messages from consumer.receive() or set MessageIdImpl explicitly","Validate messageId before wrapping/rebuilding messages in interceptors"],"tags":["pulsar","message-id","acknowledgment","invalid-message"],"backgroundTag":"null-message-id","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"}