apache/pulsar · error · UnsupportedOperationException

V5 does not support non-persistent:// topics: + topic

Error message

V5 does not support non-persistent:// topics: + topic

What it means

V5Utils.parseScalableTopicInput validates topic names before the V5 SDK uses them. Scalable topics are always backed by managed ledgers (persistent storage), and the V5 client has no code path for non-persistent topics, so any topic with the non-persistent:// domain is rejected with UnsupportedOperationException.

Source

Thrown at pulsar-client-v5/src/main/java/org/apache/pulsar/client/impl/v5/V5Utils.java:56

     * layout (regular topic that has not yet been migrated):
     * <ul>
     *   <li>{@code topic://tenant/ns/x} — explicitly scalable.</li>
     *   <li>{@code persistent://tenant/ns/x} — regular topic; if it has been migrated the
     *       broker promotes it to its {@code topic://} identity and returns the real DAG,
     *       otherwise it returns a synthetic layout that wraps the existing partitions.</li>
     *   <li>Short forms ({@code my-topic} or {@code tenant/ns/my-topic}) — normalised by
     *       {@link TopicName#get(String)} to {@code persistent://public/default/...} or
     *       {@code persistent://tenant/ns/...}; treated like any other persistent input.</li>
     * </ul>
     *
     * <p>Rejects {@code non-persistent://} with {@link UnsupportedOperationException}:
     * scalable topics are always backed by managed ledgers, and the V5 SDK has no path
     * to a non-persistent topic.
     */
    static TopicName parseScalableTopicInput(String topic) {
        TopicName tn = TopicName.get(topic);
        if (tn.getDomain() == TopicDomain.non_persistent) {
            throw new UnsupportedOperationException(
                    "V5 does not support non-persistent:// topics: " + topic);
        }
        return tn;
    }
}

View on GitHub (pinned to 820761864e)

Solutions

  1. Change the topic URL to use the persistent:// domain (scalable/V5 topics require managed-ledger-backed persistent topics).
  2. If the topic truly must be non-persistent, keep using the classic (non-V5) Pulsar client, which supports non-persistent topics.
  3. If the domain is constructed dynamically, validate/normalize it before passing the topic to V5 APIs, defaulting to persistent://.

Example fix

// before
String topic = "non-persistent://public/default/events";
client.newProducer(V5Config).topic(topic).create();
// after
String topic = "persistent://public/default/events";
client.newProducer(V5Config).topic(topic).create();
Defensive patterns

Strategy: validation

Validate before calling

if (topic.startsWith("non-persistent://")) {
    throw new IllegalArgumentException("V5 SDK requires persistent topics, got: " + topic);
}

Prevention

When it happens

Trigger: Calling a V5 SDK API that internally invokes parseScalableTopicInput with a topic string whose domain is 'non-persistent://', e.g. building a producer/consumer/reader on 'non-persistent://tenant/ns/my-topic' via the scalable-topic path.

Common situations: Migrating existing Pulsar clients that used non-persistent topics to the V5 SDK; copy-pasting topic URLs that keep the non-persistent:// prefix; configuration where the topic domain is built dynamically and defaults to non_persistent.

Related errors


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