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

  1. Inspect the topic portion of the failing URL and remove/replace invalid characters (allowed: alphanumerics, '-', '_', '.', and proper ':' scheme prefix handling).
  2. URL-encode the topic local name when building the REST request (e.g. URLEncoder.encode).
  3. Pass only the local topic name (tenant and namespace are separate path segments), not a full topic URL.
  4. 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

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


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