apache/pulsar · warning · RestException

Subscription not found on segment: ${subscription}

Error message

Subscription not found on segment: ${subscription}

What it means

HTTP 404 thrown by the segment subscription-backlog endpoint when the segment topic is loaded but has no subscription with the requested name. Backlog is per-cursor, so without the named subscription there is nothing to report.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/Segments.java:326

            @QueryParam("authoritative") @DefaultValue("false") boolean authoritative) {
        validateNamespaceName(tenant, namespace);
        TopicName segmentTopic = segmentTopicName(tenant, namespace, encodedTopic, descriptor);

        validateSuperUserAccessAsync()
                .thenCompose(__ -> validateTopicOwnershipAsync(segmentTopic, authoritative))
                .thenCompose(__ -> pulsar().getBrokerService().getTopicIfExists(segmentTopic.toString()))
                .thenAccept(optTopic -> {
                    if (optTopic.isEmpty()) {
                        // No topic loaded → no subscription cursor → no backlog. Returning
                        // 0 here would be wrong (caller might mark the segment drained on
                        // a topic that simply hasn't loaded yet); a 404 forces the caller
                        // to retry, which matches our drain-poll contract.
                        throw new RestException(Response.Status.NOT_FOUND,
                                "Segment topic not loaded: " + segmentTopic);
                    }
                    var sub = optTopic.get().getSubscription(subscription);
                    if (sub == null) {
                        throw new RestException(Response.Status.NOT_FOUND,
                                "Subscription not found on segment: " + subscription);
                    }
                    asyncResponse.resume(sub.getNumberOfEntriesInBacklog(false));
                })
                .exceptionally(ex -> {
                    log.error().attr("clientAppId", clientAppId()).attr("segment", segmentTopic)
                            .exception(ex).log("Failed to get segment subscription backlog");
                    resumeAsyncResponseExceptionally(asyncResponse, ex);
                    return null;
                });
    }

    @POST
    @Path("/{tenant}/{namespace}/{topic}/{descriptor}/subscription/{subscription}/seek")
    @Operation(summary = "Reset the segment topic's subscription cursor to the given timestamp."
            + " Super-user only.")
    @ApiResponses(value = {
            @ApiResponse(responseCode = "204", description = "Cursor reset successfully"),

View on GitHub (pinned to 820761864e)

Solutions

  1. Use the exact subscription name the consumer used (check consumer config/logs).
  2. Ensure the consuming client has connected to every segment at least once so the subscription cursor exists on each segment.
  3. Create the subscription explicitly (admin API) on the segment before polling backlog, or treat 404 as 'not draining yet'.

Example fix

// before
await getBacklog(seg, 'my-sub'); // 404: never created on this segment
// after
await admin.topics().createSubscriptionAsync(seg, 'my-sub', MessageId.earliest);
const backlog = await getBacklog(seg, 'my-sub');
Defensive patterns

Strategy: validation

Validate before calling

const subs = await admin.topics().getSubscriptionsAsync(segmentTopic);
if (!subs.includes(subscription)) throw new Error(`subscription '${subscription}' not created on ${segmentTopic}`);

Type guard

const subscriptionExists = (subs, name) => Array.isArray(subs) && subs.includes(name);

Try / catch

try {
  const backlog = await admin.scalableTopics().getSubscriptionBacklog(segmentTopic, sub);
} catch (e) {
  if (e.status === 404 && /Subscription not found/.test(e.message)) return Infinity; // not draining
  throw e;
}

Prevention

When it happens

Trigger: Polling GET backlog with a subscription name that no reader/consumer ever created on that segment — wrong subscription name, subscription not yet created on this segment (each segment has its own cursors), or the subscription was deleted/unsubscribed.

Common situations: Drain tooling assuming a subscription exists on every segment when readers only subscribed to some; typo'd subscription name; checking backlog before the consumer that creates the subscription first connected; subscribe-on-demand vs pre-created subscription mismatch.

Related errors


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