apache/pulsar · error · IllegalArgumentException
Expected MessageIdV5, got: + messageId.getClass()
Error message
Expected MessageIdV5, got: + messageId.getClass()
What it means
Transactional cumulative ack on ScalableStreamConsumer requires MessageIdV5 because its positionVector drives per-segment acks inside the (unwrapped) v4 transaction. Other MessageId implementations have no vector, so IllegalArgumentException is thrown synchronously and the transaction is unaffected.
Source
Thrown at pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/ScalableStreamConsumer.java:304
return new MessagesV5<>(receiveQueue.receiveMulti(maxNumMessages, timeout));
}
@Override
public void acknowledgeCumulative(MessageId messageId) {
if (!(messageId instanceof MessageIdV5 id)) {
throw new IllegalArgumentException("Expected MessageIdV5, got: " + messageId.getClass());
}
// Ack each segment up to the position recorded in the vector
for (var entry : id.positionVector().entrySet()) {
ackSegmentUpTo(entry.getKey(), entry.getValue(), null);
}
}
@Override
public void acknowledgeCumulative(MessageId messageId, Transaction txn) {
if (!(messageId instanceof MessageIdV5 id)) {
throw new IllegalArgumentException("Expected MessageIdV5, got: " + messageId.getClass());
}
var v4Txn = TransactionV5.unwrap(txn);
for (var entry : id.positionVector().entrySet()) {
ackSegmentUpTo(entry.getKey(), entry.getValue(), v4Txn);
}
}
/**
* Ack one segment up to the given position. Whole-segment (Exclusive) consumers ack
* cumulatively. PIP-486 bucket-shared segments are Key_Shared underneath, where cumulative acks
* are not permitted — the ack is translated into individually acking every delivered-but-unacked
* id up to the position (exactly the messages this consumer received: its buckets' share).
*/
private void ackSegmentUpTo(long segmentId, org.apache.pulsar.client.api.MessageId position,
org.apache.pulsar.client.api.transaction.Transaction v4Txn) {
// A draining consumer takes precedence: during a release the segment's slot in
// segmentConsumers is vacated (or already holds the re-subscribe chain), but the acks that
// complete the drain must still reach the consumer being drained.View on GitHub (pinned to 820761864e)
Solutions
- Use MessageIdV5 ids exclusively inside transactions on this consumer
- Convert persisted ids to MessageIdV5 (reconstructing positionVector) before acking
- Guard transactional ack code with instanceof MessageIdV5 checks
- Keep v4 and v5 transactional consumers on separate code paths
Example fix
// before
streamConsumer.acknowledgeCumulative(v4Id, txn);
// after
if (v4Id instanceof MessageIdV5 id) {
streamConsumer.acknowledgeCumulative(id, txn);
} else {
txn.abort();
throw new IllegalArgumentException("need MessageIdV5 with positionVector");
} Defensive patterns
Strategy: type-guard
Validate before calling
if (!(messageId instanceof MessageIdV5 id) || id.positionVector() == null) {
throw new IllegalArgumentException("transactional cumulative ack requires MessageIdV5");
} Type guard
static boolean isCumulativeCapable(MessageId id) {
return id instanceof MessageIdV5 v && v.positionVector() != null;
} Try / catch
try {
streamConsumer.acknowledgeCumulative(messageId, txn);
} catch (IllegalArgumentException e) {
txn.abort();
log.error("transactional cumulative ack type error", e);
} Prevention
- Use only v5 ids in transactions on this consumer
- Abort transactions when ack validation fails
- Rebuild positionVector when converting legacy ids
- Isolate v4/v5 transactional code paths
When it happens
Trigger: acknowledgeCumulative(messageId, txn) called with a non-v5 id: an id from a v4 consumer, a deserialized v4 id, or an id produced by a different stream consumer, while a transaction is open.
Common situations: Transaction spanning messages from v4 and v5 consumers; replaying recorded ids from an old storage format inside a new transaction; framework code typed on the generic MessageId API.
Related errors
- Expected MessageIdV5, got: ${messageId.getClass()}
- expected MultiMessageIdImpl object. Got instance of
- Current size and other size not equals
- Other MessageId not have topic
- Different MessageId in Map get different compare result
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/aeed9f83b02c1a61.
Report an issue: GitHub.