apache/pulsar · error · PulsarClientException.InvalidMessageException

Non-null message is required

Error message

Non-null message is required

What it means

ConsumerBase.validateMessageId(Message) rejects a null Message argument before any acknowledgment-style operation is attempted, throwing InvalidMessageException with 'Non-null message is required'. Ack operations need a real message instance to extract its MessageId, so a null reference is a caller-side programming bug rather than a broker problem.

Source

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

                break;
            }
            if (!opBatchReceive.future.isDone()) {
                opBatchReceive.future.completeExceptionally(
                        new PulsarClientException.AlreadyClosedException(
                                String.format("The consumer which subscribes the topic %s with subscription name %s was"
                                                + " already closed when cleaning and closing the consumers",
                                        topic, subscription)));
            }
        }
    }

    protected abstract Messages<T> internalBatchReceive() throws PulsarClientException;

    protected abstract CompletableFuture<Messages<T>> internalBatchReceiveAsync();

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

View on GitHub (pinned to 820761864e)

Solutions

  1. Null-check the message before calling acknowledge/reconsumeLater
  2. Fix the upstream code that produced the null reference (map miss, Optional.get, uninitialized field)
  3. Use validateMessages/validateMessageIds yourself in tests to fail fast

Example fix

// before
consumer.acknowledge(messageCache.get(id)); // may be null
// after
Message<String> msg = messageCache.get(id);
if (msg != null) {
    consumer.acknowledge(msg);
}
Defensive patterns

Strategy: validation

Validate before calling

if (message == null) {
    throw new IllegalArgumentException("Cannot ack a null message");
}
consumer.acknowledge(message);

Type guard

boolean isAckable(Message<?> m) {
    return m != null && m.getMessageId() != null;
}

Try / catch

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

Prevention

When it happens

Trigger: Calling consumer.acknowledge(null), acknowledgeCumulative(null), acknowledgeAsync(null), reconsumeLaterAsync(null, ...), validateMessageIds/validateMessages with a collection containing null — often when message comes from a map lookup or an Optional that was unwrapped unsafely.

Common situations: Caching messages in a Map<MessageId, Message> and acknowledging a missing key; passing the result of a receive() that was short-circuited; processing batched messages where a null element slipped into the list.

Related errors


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