apache/pulsar · error · PulsarClientException.InvalidMessageException
Cannot handle messages with null messageIdList
Error message
Cannot handle messages with null messageIdList
What it means
validateMessageIds(List<MessageId>) first rejects a null list with InvalidMessageException 'Cannot handle messages with null messageIdList', then validates each element. Multi-message acknowledgment (acknowledge(List<MessageId>) and transactional acks via doAcknowledgeWithTxn) requires a concrete, non-empty-capable list because the broker needs the set of IDs to ack.
Source
Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java:440
private static void validateMessageId(Message<?> message) throws PulsarClientException {
if (message == null) {
throw new PulsarClientException.InvalidMessageException("Non-null message is required");
}
if (message.getMessageId() == null) {
throw new PulsarClientException.InvalidMessageException("Cannot handle message with null messageId");
}
}
private static void validateMessageId(MessageId messageId) throws PulsarClientException {
if (messageId == null) {
throw new PulsarClientException.InvalidMessageException("Cannot handle message with null messageId");
}
}
private static void validateMessageIds(List<MessageId> messageIdList) throws PulsarClientException {
if (messageIdList == null) {
throw new PulsarClientException.InvalidMessageException("Cannot handle messages with null messageIdList");
}
for (MessageId messageId : messageIdList) {
validateMessageId(messageId);
}
}
private static void validateMessages(Messages<?> messages) throws PulsarClientException {
if (messages == null) {
throw new PulsarClientException.InvalidMessageException("Cannot handle messages with null messages");
}
for (Message<?> message : messages) {
validateMessageId(message);
}
}
@Override
public void acknowledge(Message<?> message) throws PulsarClientException {
validateMessageId(message);
acknowledge(message.getMessageId());View on GitHub (pinned to 820761864e)
Solutions
- Initialize ID collections as empty lists (Collections.emptyList()) instead of null
- Null-check the list before calling acknowledge(List<MessageId>)
- Guard the batch-ack behind a isEmpty()/!= null check
Example fix
// before
List<MessageId> ids = aggregator.getIds(); // may be null
consumer.acknowledge(ids);
// after
List<MessageId> ids = aggregator.getIds();
if (ids != null && !ids.isEmpty()) {
consumer.acknowledge(ids);
} Defensive patterns
Strategy: validation
Validate before calling
if (idList == null || idList.isEmpty()) {
return; // nothing to ack
} Type guard
boolean isAckableList(List<MessageId> ids) {
return ids != null && !ids.isEmpty() && ids.stream().allMatch(java.util.Objects::nonNull);
} Try / catch
try {
consumer.acknowledge(messageIdList);
} catch (PulsarClientException.InvalidMessageException e) {
log.warn("Invalid messageIdList: {}", e.getMessage());
} Prevention
- Initialize ID lists as empty collections, never null
- Return Collections.emptyList() instead of null from aggregation methods
- Validate list contents with a shared guard before multi-ack
When it happens
Trigger: Calling consumer.acknowledge((List<MessageId>) null) or acknowledgeAsync with a null list — usually when the list was built conditionally and never initialized, or a method parameter was forwarded without checking.
Common situations: Aggregating IDs for batch acking where the aggregation step returned null instead of an empty list; refactoring from single-ack to batch-ack while keeping old nullable variables.
Related errors
- Cannot handle messages with null messages
- Non-null message is required
- Cannot handle message with null messageId
- isDuplicated cannot accept
- tlsPolicy purpose and policy must not be null
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/0b84212ab302bb26.
Report an issue: GitHub.