apache/pulsar · error · IllegalArgumentException

Need to provide a non-persistent topic name

Error message

Need to provide a non-persistent topic name

What it means

The mirror of the persistent check: CliCommand.validateNonPersistentTopic requires the topic argument to parse to TopicDomain.non_persistent (non-persistent://tenant/namespace/topic). Any other domain (including the default persistent domain) causes an immediate IllegalArgumentException.

Source

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

        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(":");
        try {
            com.google.common.base.Preconditions.checkArgument(messageId.length == 2);
            return new MessageIdImpl(Long.parseLong(messageId[0]), Long.parseLong(messageId[1]), partitionIndex);
        } catch (Exception e) {
            throw new PulsarAdminException(
                    "Invalid message id (must be in format: ledgerId:entryId) value " + resetMessageIdStr);
        }
    }

View on GitHub (pinned to 820761864e)

Solutions

  1. Prefix the topic explicitly: non-persistent://tenant/namespace/topic
  2. If the topic is actually persistent, use the persistent-topic command instead
  3. Script a domain check on the topic string before invoking the CLI
  4. Avoid short topic names in admin scripts so the domain is never defaulted unexpectedly

Example fix

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

Strategy: validation

Validate before calling

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

Try / catch

try {
    admin.topics().getStats(topic);
} catch (IllegalArgumentException e) {
    log.error("{} — prefix topic with non-persistent://", e.getMessage());
}

Prevention

When it happens

Trigger: Running a non-persistent-topic-only admin command with a topic name of the form persistent://tenant/namespace/topic or a short name that defaults to the persistent domain.

Common situations: Forgetting the non-persistent:// prefix when issuing non-persistent-specific admin commands (e.g. stats or lookups on non-persistent topics); mixing up which commands accept which domain in scripts; docs examples showing short topic names.

Related errors


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