apache/pulsar · error · IllegalArgumentException

Invalid namespace format. namespace: ${namespace}

Error message

Invalid namespace format. namespace: ${namespace}

What it means

NamespaceName parses names in the V2 form '<tenant>/<namespace>'. This throw fires when the split on '/' yields anything other than 2 or 3 parts (e.g. no slash, or more than two slashes), i.e. the string is not a well-formed namespace name. It is immediately re-wrapped by the catch block with the fuller 'expected <tenant>/<namespace>' message, so callers normally see the wrapped variant.

Source

Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/naming/NamespaceName.java:104

    @SuppressFBWarnings("DCN_NULLPOINTER_EXCEPTION")
    private NamespaceName(String namespace) {
        // Verify it's a proper namespace
        // The namespace name is composed of <tenant>/<namespace>
        try {

            String[] parts = namespace.split("/");
            if (parts.length == 2) {
                validateNamespaceName(parts[0], parts[1]);

                tenant = parts[0];
                localName = parts[1];
            } else if (parts.length == 3) {
                throw new IllegalArgumentException(
                    "V1 namespace names (with cluster component) are no longer supported. "
                    + "Please use the V2 format: '<tenant>/<namespace>'. Got: " + namespace);
            } else {
                throw new IllegalArgumentException("Invalid namespace format. namespace: " + namespace);
            }
        } catch (IllegalArgumentException | NullPointerException e) {
            throw new IllegalArgumentException("Invalid namespace format."
                    + " expected <tenant>/<namespace>"
                    + " but got: " + namespace, e);
        }
        this.namespace = namespace;
    }

    public String getTenant() {
        return tenant;
    }

    public String getLocalName() {
        return localName;
    }

    public String getPersistentTopicName(String localTopic) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Format the name as '<tenant>/<namespace>' with exactly one slash, e.g. NamespaceName.get("public/default").
  2. Check the config/env source: if the value is null, empty, or missing the slash, fix the configuration before constructing the NamespaceName.
  3. If you have separate tenant and namespace strings, build with NamespaceName.get(tenant, namespace) instead of string concatenation.
  4. If you hold a legacy V1 name (tenant/cluster/namespace), migrate to the V2 form by dropping the cluster component.

Example fix

// before
NamespaceName ns = NamespaceName.get("my-tenant");
// after
NamespaceName ns = NamespaceName.get("my-tenant/my-namespace");
Defensive patterns

Strategy: validation

Validate before calling

boolean isValidNamespaceString(String ns) {
    return ns != null && ns.chars().filter(c -> c == '/').count() == 1
            && !ns.startsWith("/") && !ns.endsWith("/");
}
// use: if (isValidNamespaceString(input)) NamespaceName.get(input);

Type guard

static boolean isWellFormedNamespace(String ns) {
    if (ns == null) return false;
    String[] parts = ns.split("/", -1);
    return parts.length == 2 && !parts[0].isEmpty() && !parts[1].isEmpty();
}

Try / catch

try {
    NamespaceName ns = NamespaceName.get(input);
} catch (IllegalArgumentException e) {
    log.warn("Rejected namespace '{}': {}", input, e.getMessage());
    // fail fast or substitute a validated default
}

Prevention

When it happens

Trigger: Calling NamespaceName.get(String) or new via the public factory with a string containing zero '/' (e.g. 'my-tenant') or 4+ segments (e.g. 'a/b/c/d'), or with a null string (NPE caught and rethrown as this path's wrapper).

Common situations: Passing a bare topic or tenant name instead of tenant/namespace; reading a namespace from a config property/env var that was never set (yields 'null' or empty); concatenating tenant and namespace with the wrong separator; V1-style names edited incorrectly leaving extra slashes.

Related errors


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