apache/pulsar · error · IllegalArgumentException
Not supported operation on partitioned-topic
Error message
Not supported operation on partitioned-topic
What it means
ResetCursorData's constructor extracts ledgerId, entryId, batchIndex, and partitionIndex from a MessageId by casting it to MessageIdAdv. If the caller passes a TopicMessageId — the aggregated message id type used when consuming a partitioned topic — the code rejects it because a TopicMessageId does not carry a single partition's raw position suitable for cursor reset.
Source
Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/ResetCursorData.java:78
this.entryId = Long.MAX_VALUE;
} else if ("earliest".equals(position)) {
this.ledgerId = -1;
this.entryId = -1;
} else {
throw new IllegalArgumentException(
String.format("Invalid value %s for the position. Allowed values are [latest, earliest]",
position));
}
}
public ResetCursorData(MessageId messageId) {
MessageIdAdv messageIdAdv = (MessageIdAdv) messageId;
this.ledgerId = messageIdAdv.getLedgerId();
this.entryId = messageIdAdv.getEntryId();
this.batchIndex = messageIdAdv.getBatchIndex();
this.partitionIndex = messageIdAdv.getPartitionIndex();
if (messageId instanceof TopicMessageId) {
throw new IllegalArgumentException("Not supported operation on partitioned-topic");
}
}
}
View on GitHub (pinned to 820761864e)
Solutions
- Unwrap the TopicMessageId to its underlying partition message id (e.g. topicMessageId.getInnerMessageId() or cast the TopicMessageId and get the partition-specific MessageId) before constructing ResetCursorData.
- Obtain the message id directly from a consumer attached to the specific partition (partition-i topic) rather than from the aggregated partitioned-topic consumer.
- If the topic is partitioned and you intend to reset the whole topic, use the partition-aware admin API instead of ResetCursorData with a single message id.
Example fix
// before
MessageId id = message.getMessageId(); // TopicMessageId on partitioned topic
ResetCursorData data = new ResetCursorData(id);
// after
MessageId id = message.getMessageId();
if (id instanceof TopicMessageId) {
id = ((TopicMessageId) id).getInnerMessageId();
}
ResetCursorData data = new ResetCursorData(id); Defensive patterns
Strategy: type-guard
Validate before calling
if (messageId instanceof TopicMessageId) {
throw new IllegalArgumentException("Pass the partition-level message id, not a TopicMessageId");
} Type guard
static MessageId requirePartitionMessageId(MessageId id) {
return id instanceof TopicMessageId ? ((TopicMessageId) id).getInnerMessageId() : id;
} Prevention
- Always unwrap TopicMessageId before low-level MessageIdAdv operations.
- Add an instanceof TopicMessageId check at every boundary where message ids leave consumer code.
- Prefer getting ids from a partition-specific consumer when doing cursor/seek operations.
When it happens
Trigger: Calling the ResetCursorData constructor (directly or via an admin/client API that builds one) with a MessageId obtained from a consumer subscribed to a partitioned topic, i.e. an instance of TopicMessageId, instead of the underlying partition-level message id.
Common situations: Consuming a partitioned topic and passing message.getMessageId() straight into a reset-cursor / seek style call without unwrapping it to the partition's MessageIdAdv; code written against a non-partitioned topic then reused against a partitioned topic.
Related errors
- The shared resource doesn't support thread pool configurati
- No resources have been configured while using shareConfigure
- Ranges must be [0, 65535] but provided range is
- Key hash ranges with overlap between and
- Invalid value %s for the position. Allowed values are [lates
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/ad5d3f249159bb20.
Report an issue: GitHub.