apache/pulsar · warning · RestException

Partitioned Topic Name should not contain '-partition-'

Error message

Partitioned Topic Name should not contain '-partition-'

What it means

The broker admin REST endpoint getPartitionedStats for non-persistent topics rejects requests whose topic name contains the '-partition-' segment (i.e. the caller passed an individual partition of a partitioned topic instead of the base partitioned topic name). Partition-level stats are only reachable via the parent partitioned topic, so the broker fails fast with HTTP 412 PRECONDITION_FAILED.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/NonPersistentTopics.java:279

            @Parameter(description = "Get per partition stats")
            @QueryParam("perPartition") @DefaultValue("true") boolean perPartition,
            @Parameter(description = "Whether leader broker redirected this call to this broker. For internal use.")
            @QueryParam("authoritative") @DefaultValue("false") boolean authoritative,
            @Parameter(description = "If return precise backlog or imprecise backlog")
            @QueryParam("getPreciseBacklog") @DefaultValue("false") boolean getPreciseBacklog,
            @Parameter(description = "If return backlog size for each subscription, require locking on ledger so be "
                    + "careful not to use when there's heavy traffic.")
            @QueryParam("subscriptionBacklogSize") @DefaultValue("false") boolean subscriptionBacklogSize,
            @Parameter(description = "If return the earliest time in backlog")
            @QueryParam("getEarliestTimeInBacklog") @DefaultValue("false") boolean getEarliestTimeInBacklog,
            @Parameter(description = "If exclude the publishers")
            @QueryParam("excludePublishers") @DefaultValue("false") boolean excludePublishers,
            @Parameter(description = "If exclude the consumers")
            @QueryParam("excludeConsumers") @DefaultValue("false") boolean excludeConsumers) {
        try {
            validateTopicName(tenant, namespace, encodedTopic);
            if (topicName.isPartitioned()) {
                throw new RestException(Response.Status.PRECONDITION_FAILED,
                        "Partitioned Topic Name should not contain '-partition-'");
            }
            try {
                validateGlobalNamespaceOwnership(namespaceName);
            } catch (Exception e) {
                log.error()
                        .attr("topic", topicName)
                        .exception(e)
                        .log("Failed to get partitioned stats");
                resumeAsyncResponseExceptionally(asyncResponse, e);
                return;
            }
            getPartitionedTopicMetadataAsync(topicName,
                    authoritative, false).thenAccept(partitionMetadata -> {
                if (partitionMetadata.partitions == 0) {
                    asyncResponse.resume(new RestException(Status.NOT_FOUND,
                            String.format("Partitioned topic not found %s", topicName.toString())));
                    return;

View on GitHub (pinned to 820761864e)

Solutions

  1. Use the base partitioned topic name (strip the '-partition-N' suffix) when calling the partitioned-stats endpoint
  2. To inspect a single partition, use the regular per-topic stats endpoint instead of the partitioned-stats one
  3. Strip suffix client-side, e.g. name.replaceAll("-partition-\\d+$", "") before the call

Example fix

// before
GET /admin/v2/namespaces/public/default/my-topic-partition-0/partitioned-stats
// after
GET /admin/v2/namespaces/public/default/my-topic/partitioned-stats
Defensive patterns

Strategy: validation

Validate before calling

if (topic.contains("-partition-")) throw new IllegalArgumentException("Use base partitioned topic name, not a partition: " + topic);
String base = topic.replaceAll("-partition-\\d+$", "");

Type guard

boolean isBasePartitionedTopic(String t) { return t != null && !t.matches(".*-partition-\\d+$"); }

Try / catch

try { stats = admin.topics().getPartitionedStats(baseTopic, ...); } catch (PulsarAdminException e) { if (e.getStatusCode() == 412) { /* fix topic name */ } throw e; }

Prevention

When it happens

Trigger: Calling GET /admin/v2/namespaces/{tenant}/{namespace}/{non-persistent-topic}/partitioned-stats with encodedTopic containing '-partition-N' (e.g. persistent:// is not used here; my-topic-partition-0).

Common situations: Scripts or dashboards that iterate over individual partitions discovered from stats output and then query partitioned stats per partition; client code that confuses topicName.toString() of a partition with the partitioned topic name.

Related errors


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