apache/pulsar · error · IllegalArgumentException

Need to provide a persistent topic name

Error message

Need to provide a persistent topic name

What it means

The pulsar-admin CLI command validates that the topic argument parses to a topic whose domain is persistent (persistent://tenant/namespace/topic). If the supplied topic is non-persistent (or lacks a domain so it cannot be confirmed persistent), CliCommand.validatePersistentTopic throws IllegalArgumentException before the admin operation runs.

Source

Thrown at pulsar-client-tools/src/main/java/org/apache/pulsar/admin/cli/CliCommand.java:56

import picocli.CommandLine.Model.CommandSpec;
import picocli.CommandLine.Spec;

public abstract class CliCommand implements Callable<Integer> {
    @Spec
    private CommandSpec commandSpec;

    static String validateNamespace(String namespace) {
        return NamespaceName.get(namespace).toString();
    }

    static String validateTopicName(String topic) {
        return TopicName.get(topic).toString();
    }

    static String validatePersistentTopic(String topic) {
        TopicName topicName = TopicName.get(topic);
        if (topicName.getDomain() != TopicDomain.persistent) {
            throw new IllegalArgumentException("Need to provide a persistent topic name");
        }
        return topicName.toString();
    }

    static String validateNonPersistentTopic(String topic) {
        TopicName topicName = TopicName.get(topic);
        if (topicName.getDomain() != TopicDomain.non_persistent) {
            throw new IllegalArgumentException("Need to provide a non-persistent topic name");
        }
        return topicName.toString();
    }

    static MessageId validateMessageIdString(String resetMessageIdStr) throws PulsarAdminException {
        return validateMessageIdString(resetMessageIdStr, -1);
    }

    static MessageId validateMessageIdString(String resetMessageIdStr, int partitionIndex) throws PulsarAdminException {
        String[] messageId = resetMessageIdStr.split(":");

View on GitHub (pinned to 820761864e)

Solutions

  1. Use the full persistent topic URL: persistent://tenant/namespace/topic
  2. If the topic really is non-persistent, use the corresponding non-persistent admin command/endpoint instead
  3. Check your broker's default topic domain configuration if you are relying on short topic names
  4. Echo/validate the topic argument in your script before invoking the CLI

Example fix

// before
pulsar-admin topics stats non-persistent://public/default/my-topic
// after
pulsar-admin topics stats persistent://public/default/my-topic
Defensive patterns

Strategy: validation

Validate before calling

// Validate topic domain before invoking the CLI/admin command
if (!topic.startsWith("persistent://")) {
    throw new IllegalArgumentException("This command requires a persistent topic, got: " + topic);
}

Try / catch

try {
    admin.topics().getStats(topic);
} catch (IllegalArgumentException e) {
    log.error("{} — use persistent://tenant/namespace/topic", e.getMessage());
}

Prevention

When it happens

Trigger: Running a persistent-topic-only admin command (e.g. certain lookups, stats, or subscriptions commands) with a topic URL of the form non-persistent://tenant/namespace/topic, or a bare short name that resolves to a non-persistent default domain.

Common situations: Copy-pasting a topic name from a non-persistent producer config; omitting the persistent:// prefix and relying on a broker configuration whose default domain is non-persistent; scripting admin commands against a mix of persistent and non-persistent topics.

Related errors


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