apache/pulsar · warning · RestException
Reset-cursor at position is not allowed for partitioned-topi
Error message
Reset-cursor at position is not allowed for partitioned-topic
What it means
The broker admin REST API rejects a cursor reset-to-position request issued against the base name of a partitioned topic. Partitioned topics are a logical grouping of individual partition topics, and cursors live on each concrete partition, so a position-based reset has no valid target. The check happens after fetching partitioned-topic metadata: if partitions > 0, a 405 METHOD_NOT_ALLOWED RestException is thrown.
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java:2763
resumeAsyncResponseExceptionally(asyncResponse, ex);
return null;
});
}
protected void internalResetCursorOnPosition(AsyncResponse asyncResponse, String subName, boolean authoritative,
MessageIdImpl messageId, boolean isExcluded, int batchIndex) {
validateTopicOperationAsync(topicName, TopicOperation.RESET_CURSOR, subName)
.thenCompose(__ -> {
// If the topic name is a partition name, no need to get partition topic metadata again
if (!topicName.isPartitioned()) {
return getPartitionedTopicMetadataAsync(topicName, authoritative, false)
.thenCompose(topicMetadata -> {
if (topicMetadata.partitions > 0) {
log.warn()
.attr("topic", topicName)
.attr("subscription", subName)
.log("Not supported operation on partitioned-topic");
throw new CompletionException(new RestException(Status.METHOD_NOT_ALLOWED,
"Reset-cursor at position is not allowed for partitioned-topic"));
}
return CompletableFuture.completedFuture(null);
});
} else {
return CompletableFuture.completedFuture(null);
}
}).thenCompose(__ -> validateGlobalNamespaceOwnershipAsync(namespaceName))
.thenCompose(__ -> {
log.info()
.attr("topic", topicName)
.attr("subscription", subName)
.attr("position", messageId)
.log("received reset cursor on subscription to position");
return validateTopicOwnershipAsync(topicName, authoritative);
}).thenCompose(ignore -> getTopicReferenceAsync(topicName))
.thenAccept(topic -> {
if (topic == null) {View on GitHub (pinned to 820761864e)
Solutions
- Call the reset endpoint on a concrete partition (e.g. my-topic-partition-0) rather than the partitioned topic base name
- Or use the non-position reset endpoint POST .../subscription/{sub}/reset_by_timestamp which supports partitioned topics via per-partition fan-out
- List partitions via GET /admin/v2/persistent/{ns}/{topic}/partitions and iterate them, resetting each individually
Example fix
// before
admin.topics().resetCursorByPosition("persistent://public/default/my-topic", "my-sub", position);
// after
for (String part : admin.topics().getPartitionedPartitions("persistent://public/default/my-topic")) {
admin.topics().resetCursorByPosition(part, "my-sub", position);
} Defensive patterns
Strategy: validation
Validate before calling
PartitionedTopicMetadata md = admin.topics().getPartitionedMetadata(topic);
if (md.partitions > 0) throw new IllegalArgumentException("Use a concrete partition, e.g. " + topic + "-partition-0");
admin.topics().resetCursorByPosition(topic, sub, position); Type guard
boolean isPartitionedBase(String topic) throws Exception {
return admin.topics().getPartitionedMetadata(topic).partitions > 0;
} Prevention
- Always resolve partitioned topics to their partition list before per-partition admin ops
- Prefer reset-by-timestamp for partitioned subscriptions
- Keep the full partition suffix in any persisted topic reference
When it happens
Trigger: Calling the admin endpoint POST /admin/v2/persistent/{tenant}/{namespace}/{topic}/subscription/{sub}/reset_by_position (or internalPersistentTopicsBase resetCursorAtPosition) with the parent partitioned topic name instead of a specific partition like topic-partition-0.
Common situations: Scripts that iterate topics and forget to append -partition-N; client libraries (e.g. Java/Python admin clients) passing the cluster-level topic name; tooling that resolves a partitioned topic from a subscription list and reuses it verbatim.
Related errors
- GetMessageById is not allowed on partitioned-topic
- Get message ID by timestamp on a partitioned topic is not al
- Peek messages on a partitioned topic is not allowed
- Examine messages on a partitioned topic is not allowed, plea
- Get message ID by timestamp on a non-persistent topic is not
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/13e0ddc3ebb5e855.
Report an issue: GitHub.