apache/pulsar · error · IllegalArgumentException
V1 topic names (with cluster component) are no longer suppor
Error message
V1 topic names (with cluster component) are no longer supported. Please use the V2 format: '<domain>://tenant/namespace/topic'. Got: ${topic} What it means
toFullTopicName validates/normalizes a topic string to the full V2 form. Pulsar dropped support for V1 topic names, which included a cluster segment ('domain://tenant/cluster/namespace/topic'). If the string after '://' splits into exactly 4 segments (i.e. it still has the cluster component), the method throws this IllegalArgumentException directing the user to the V2 format.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/naming/TopicName.java:555
}
/**
* Convert a topic name to a full topic name.
* In Pulsar, a full topic name is "<domain>://<tenant>/<namespace>/<local-topic>".
* For convenience, clients can pass a short topic name:
* - "<local-topic>", which represents "persistent://public/default/<local-topic>"
* - "<tenant>/<namespace>/<local-topic>", which represents "persistent://<tenant>/<namespace>/<local-topic>"
*
* @param topic the topic name from client
* @return the full topic name.
*/
public static String toFullTopicName(String topic) {
final int index = topic.indexOf("://");
if (index >= 0) {
TopicDomain.getEnum(topic.substring(0, index));
final List<String> parts = splitBySlash(topic.substring(index + "://".length()), 4);
if (parts.size() == 4) {
throw new IllegalArgumentException(
"V1 topic names (with cluster component) are no longer supported. "
+ "Please use the V2 format: '<domain>://tenant/namespace/topic'. Got: " + topic);
}
if (parts.size() != 3) {
throw new IllegalArgumentException(topic + " is invalid. "
+ "Expected format: '<domain>://tenant/namespace/topic'");
}
NamespaceName.validateNamespaceName(parts.get(0), parts.get(1));
if (StringUtils.isBlank(parts.get(2))) {
throw new IllegalArgumentException(topic + " has blank local topic");
}
return topic; // it's a valid full topic name
} else {
List<String> parts = splitBySlash(topic, 0);
if (parts.size() != 1 && parts.size() != 3) {
throw new IllegalArgumentException(topic + " is invalid");
}
if (parts.size() == 1) {View on GitHub (pinned to 820761864e)
Solutions
- Remove the cluster segment: convert 'domain://tenant/cluster/namespace/topic' to 'domain://tenant/namespace/topic'
- Update legacy configs/scripts/clients to the V2 format
- If cluster information matters, use V2 namespaces (tenant/namespace) which encode the cluster policy differently
Example fix
// before
TopicName.toFullTopicName("persistent://my-tenant/us-west/my-ns/my-topic");
// after
TopicName.toFullTopicName("persistent://my-tenant/my-ns/my-topic"); Defensive patterns
Strategy: validation
Validate before calling
public static void requireNoClusterSegment(String topic) {
int i = topic.indexOf("://");
if (i >= 0 && topic.substring(i + 3).split("/").length == 4) {
throw new IllegalArgumentException("V1 topic name with cluster segment: " + topic);
}
} Type guard
public static boolean isV2TopicName(String s) {
int i = s == null ? -1 : s.indexOf("://");
return i >= 0 && s.substring(i + 3).split("/").length == 3;
} Try / catch
try {
String full = TopicName.toFullTopicName(legacyTopic);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("V1 topic names")) {
String[] p = legacyTopic.substring(legacyTopic.indexOf("://") + 3).split("/");
legacyTopic = legacyTopic.substring(0, legacyTopic.indexOf("://") + 3) + p[0] + "/" + p[2] + "/" + p[3]; // drop cluster
}
} Prevention
- Migrate all Pulsar 1.x configs/scripts to V2 names before upgrading clients
- Search configs for topic URLs with 4 segments after '://'
- Remember the cluster field was removed in Pulsar 2.0; namespaces replace it
When it happens
Trigger: Calling TopicName.toFullTopicName() (or APIs that route through it) with a legacy V1 name like 'persistent://my-tenant/us-west/my-ns/my-topic' — 4 path segments after the domain.
Common situations: Migrating old Pulsar 1.x configurations, scripts, or clients to Pulsar 2.x+; old documentation/bookmarks; data exported from a legacy cluster still carrying cluster-scoped topic names.
Related errors
- Invalid topic name: %s. Topic local name must not be blank.
- Invalid topic name: ${completeTopicName}
- ${topic} is invalid. Expected format: '<domain>://tenant/nam
- ${topic} has blank local topic
- ${topic} is invalid
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/019fd14af114f340.
Report an issue: GitHub.