apache/pulsar · error · IllegalArgumentException

invalid null domain

Error message

invalid null domain

What it means

NamespaceName.getTopicName(domain, topic) composes 'domain://namespace/topic' and throws this IllegalArgumentException when the TopicDomain argument is null. It is a defensive programmer-error check: a null domain cannot produce a valid topic URL.

Source

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

    public String getLocalName() {
        return localName;
    }

    public String getPersistentTopicName(String localTopic) {
        return getTopicName(TopicDomain.persistent, localTopic);
    }

    /**
     * Compose the topic name from namespace + topic.
     *
     * @param domain
     * @param topic
     * @return
     */
    String getTopicName(TopicDomain domain, String topic) {
        if (domain == null) {
            throw new IllegalArgumentException("invalid null domain");
        }
        NamedEntity.checkName(topic);
        return String.format("%s://%s/%s", domain.toString(), namespace, topic);
    }

    @Override
    public String toString() {
        return namespace;
    }

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

        return false;

View on GitHub (pinned to 820761864e)

Solutions

  1. Pass an explicit TopicDomain, typically TopicDomain.persistent for normal topics, e.g. namespace.getPersistentTopicName(topic).
  2. If the domain comes from a string, map it defensively: TopicDomain.valueOf(str) with a null/empty check or default to persistent.
  3. Check whether the calling code path should have used a higher-level TopicName API instead of constructing the name manually.

Example fix

// before
TopicDomain domain = lookupDomain(cfg); // may return null
String name = ns.getTopicName(domain, topic);
// after
TopicDomain domain = Optional.ofNullable(lookupDomain(cfg)).orElse(TopicDomain.persistent);
String name = ns.getTopicName(domain, topic);
Defensive patterns

Strategy: type-guard

Validate before calling

if (domain == null) {
    domain = TopicDomain.persistent; // or reject the input earlier
}
String name = ns.getTopicName(domain, topic);

Type guard

static TopicDomain requireDomain(TopicDomain d) {
    if (d == null) throw new IllegalArgumentException("TopicDomain is required");
    return d;
}

Try / catch

try {
    String name = ns.getTopicName(domain, topic);
} catch (IllegalArgumentException e) {
    if ("invalid null domain".equals(e.getMessage())) {
        domain = TopicDomain.persistent;
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Invoking getPersistentTopicName / package-private getTopicName with a null TopicDomain, e.g. passing an unset enum variable or the result of a lookup that returned null instead of TopicDomain.persistent.

Common situations: Code that resolves TopicDomain from config or a string via valueOf with a null input; refactored code where a domain constant became null; building topic names generically where the domain parameter is optional elsewhere but required here.

Related errors


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