apache/pulsar · error · IllegalArgumentException

Invalid namespace format. namespace: %s/%s

Error message

Invalid namespace format. namespace: %s/%s

What it means

NamespaceName.validateNamespaceName(tenant, namespace) validates the two components of a V2 namespace name. It throws this IllegalArgumentException when either the tenant or the namespace part is null or empty, formatting them as 'tenant/namespace' in the message. After the null/empty check it also runs NamedEntity.checkName on both parts.

Source

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

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof NamespaceName) {
            NamespaceName other = (NamespaceName) obj;
            return Objects.equals(namespace, other.namespace);
        }

        return false;
    }

    @Override
    public int hashCode() {
        return namespace.hashCode();
    }

    public static void validateNamespaceName(String tenant, String namespace) {
        if ((tenant == null || tenant.isEmpty()) || (namespace == null || namespace.isEmpty())) {
            throw new IllegalArgumentException(
                    String.format("Invalid namespace format. namespace: %s/%s", tenant, namespace));
        }
        NamedEntity.checkName(tenant);
        NamedEntity.checkName(namespace);
    }

    @Override
    public NamespaceName getNamespaceObject() {
        return this;
    }

    @Override
    public boolean includes(TopicName topicName) {
        return this.equals(topicName.getNamespaceObject());
    }
}

View on GitHub (pinned to 820761864e)

Solutions

  1. Supply both a non-null, non-empty tenant and namespace, e.g. NamespaceName.get("public", "default").
  2. Trim/normalize inputs from config and treat empty strings as missing values before constructing.
  3. If components come from splitting a string, verify the string contains a non-empty segment on each side of '/'.
  4. Use NamespaceName.isValid or try-catch around construction when input origin is untrusted.

Example fix

// before
String tenant = config.get("tenant"); // ""
NamespaceName ns = NamespaceName.get(tenant, "default");
// after
String tenant = config.get("tenant");
NamespaceName ns = (tenant == null || tenant.isEmpty())
        ? NamespaceName.get("public", "default")
        : NamespaceName.get(tenant, "default");
Defensive patterns

Strategy: validation

Validate before calling

void requireNonEmpty(String v, String what) {
    if (v == null || v.isEmpty()) {
        throw new IllegalArgumentException(what + " must be non-empty");
    }
}
// call before: requireNonEmpty(tenant, "tenant"); requireNonEmpty(localName, "namespace");
NamespaceName.validateNamespaceName(tenant, localName);

Type guard

static boolean hasValidComponents(String tenant, String ns) {
    return tenant != null && !tenant.isEmpty() && ns != null && !ns.isEmpty();
}

Try / catch

try {
    NamespaceName.validateNamespaceName(tenant, localName);
} catch (IllegalArgumentException e) {
    throw new IllegalArgumentException("Both tenant and namespace must be non-empty; got tenant='" + tenant + "' namespace='" + localName + "'", e);
}

Prevention

When it happens

Trigger: Calling NamespaceName.get(tenant, namespace) with null or empty tenant, or null or empty namespace — e.g. NamespaceName.get(null, "default") or NamespaceName.get("public", ""). Also triggered from the NamespaceName(String) parsing path when a segment of a 'a/b' name is empty (e.g. 'public/' or '/default').

Common situations: Configuration where tenant or namespace keys are unset and default to empty strings; splitting a namespace string that has an empty segment; templated service URLs where variables were not substituted; programmatic client construction with unset builder fields.

Related errors


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