apache/pulsar · error · org.apache.pulsar.broker.admin.RestException
Topic name is not valid
Error message
Topic name is not valid
What it means
Thrown by validateTopicName when the fully-qualified topic name built from tenant/namespace/localName does not parse as a valid Pulsar topic name. Pulsar enforces naming rules (allowed characters, structure like tenant/namespace/topic) before any topic operation proceeds, returning HTTP 412 Precondition Failed.
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/AdminResource.java:247
.attr("namespace", namespaceName)
.exceptionMessage(e)
.log("Failed to validate global cluster configuration");
throw new RestException(Status.SERVICE_UNAVAILABLE, "Failed to validate global cluster configuration");
}
}
protected void validateTopicName(String tenant, String namespace, String encodedTopic) {
String topic = Codec.decode(encodedTopic);
try {
this.namespaceName = NamespaceName.get(tenant, namespace);
this.topicName = TopicName.get(domain(), namespaceName, topic);
} catch (IllegalArgumentException e) {
log.warn()
.attr("domain", domain())
.attr("tenant", tenant)
.attr("namespace", namespace)
.attr("topic", topic)
.log("Invalid topic name");
throw new RestException(Status.PRECONDITION_FAILED, "Topic name is not valid");
}
}
/**
* Validates that a topic can be created.
*
* <p>This is the single source of truth for topic-creation name validation shared by every admin create
* endpoint (persistent, non-persistent and scalable topics). Rejecting here keeps topics which could never be
* reached (e.g. because clients trim topic names) from being created. The transaction-internal-name rule is
* gated on {@link TopicDomain#persistent} so it stays specific to persistent topics, while the whitespace
* validation applies uniformly to all topic types.
*/
protected void validateCreateTopic(TopicName topicName) {
if (topicName.getDomain() == TopicDomain.persistent
&& SystemTopicNames.isTransactionInternalName(topicName)) {
log.warn().attr("topic", topicName).log("Forbidden to create transaction internal topic");
throw new RestException(Status.BAD_REQUEST, "Cannot create topic in system topic format!");
}View on GitHub (pinned to 820761864e)
Solutions
- Inspect the topic portion of the failing URL and remove/replace invalid characters (allowed: alphanumerics, '-', '_', '.', and proper ':' scheme prefix handling).
- URL-encode the topic local name when building the REST request (e.g. URLEncoder.encode).
- Pass only the local topic name (tenant and namespace are separate path segments), not a full topic URL.
- If using the Java client, use TopicName.get(...) to validate the name client-side before calling admin APIs.
Example fix
// before String topic = "orders/eu 2024"; admin.topics().createPartitionedTopic(topic, 4); // after String topic = "orders-eu-2024"; admin.topics().createPartitionedTopic(topic, 4);
Defensive patterns
Strategy: validation
Validate before calling
// Java: validate the topic name before calling the REST API
import org.apache.pulsar.common.naming.TopicName;
public static boolean isValidTopicLocalName(String tenant, String ns, String local) {
try {
TopicName.get("persistent", tenant, ns, local);
return true;
} catch (IllegalArgumentException e) {
return false;
}
} Type guard
static boolean safeTopicName(String t) {
return t != null && !t.isBlank() && t.matches("[A-Za-z0-9._:-]+") && !t.contains(" ");
} Try / catch
try {
admin.topics().getStats(fqTopic);
} catch (PulsarAdminException e) {
if (e.getStatusCode() == 412) {
log.error("Invalid topic name: {}", fqTopic);
}
} Prevention
- URL-encode topic local names when building REST paths.
- Reject user-supplied topic names at the application boundary with a regex whitelist.
- Never interpolate full topic URIs into admin client calls; pass tenant/ns/local separately.
- Add unit tests for topic-name sanitization.
When it happens
Trigger: Calling persistent/non-persistent topic REST endpoints with a topic local name containing illegal characters (e.g. spaces, '*'), an empty local name, or a malformed encoded topic portion, e.g. PUT /admin/v2/persistent/my-tenant/my-ns/bad topic or topics/... with 'my-topic%2F' escapes that break parsing.
Common situations: Client code interpolating un-sanitized user input into topic URLs; missing URL-encoding of special characters; accidentally passing the full topic URL instead of just the local name; legacy clients using characters disallowed by newer Pulsar name validation.
Related errors
- Partitioned Topic Name should not contain '-partition-'
- Invalid value for message TTL
- interval must be greater than or equal to 0
- maxProducersPerTopic must be 0 or more
- maxConsumersPerTopic must be 0 or more
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/9de84dbd1d80d1bf.
Report an issue: GitHub.