apache/pulsar · error · PulsarClientException.InvalidMessageException

Cannot handle messages with null messages

Error message

Cannot handle messages with null messages

What it means

validateMessages(Messages<?>) rejects a null Messages collection with InvalidMessageException 'Cannot handle messages with null messages' before iterating elements. It is used by the batch-acknowledgment path consumer.acknowledge(Messages), so a null Messages object is rejected up front as a caller bug.

Source

Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/ConsumerBase.java:449

    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());
    }

    @Override
    public void acknowledge(MessageId messageId) throws PulsarClientException {
        validateMessageId(messageId);
        try {
            acknowledgeAsync(messageId).get();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();

View on GitHub (pinned to 820761864e)

Solutions

  1. Null-check the Messages object before calling acknowledge(Messages)
  2. Ensure batchReceive() results are captured and validated before acking
  3. Return an empty Messages instance instead of null from wrapper methods

Example fix

// before
consumer.acknowledge(pendingBatch); // may be null
// after
if (pendingBatch != null) {
    consumer.acknowledge(pendingBatch);
}
Defensive patterns

Strategy: validation

Validate before calling

if (messages == null) {
    return; // or throw IllegalArgumentException
}

Type guard

boolean isAckableBatch(Messages<?> msgs) {
    return msgs != null;
}

Try / catch

try {
    consumer.acknowledge(messages);
} catch (PulsarClientException.InvalidMessageException e) {
    log.warn("Invalid messages collection for ack: {}", e.getMessage());
}

Prevention

When it happens

Trigger: Calling consumer.acknowledge((Messages<?>) null), typically when the Messages came from batchReceive() that was short-circuited, or a wrapper method forwards a null result.

Common situations: Storing the result of batchReceiveAsync().get() where an exception path yields null; conditional batch processing where the Messages variable is only assigned in one branch.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/7572669a22f92b64. Report an issue: GitHub.