apache/pulsar · error · IllegalArgumentException
Invalid topic name: ${completeTopicName}
Error message
Invalid topic name: ${completeTopicName} What it means
When parsing the topic name throws a NullPointerException internally (e.g. a null or badly-structured input where an expected segment is absent), TopicName's constructor catches the NPE and rethrows it as an IllegalArgumentException with the message 'Invalid topic name: <input>', preserving the NPE as the cause. It exists so callers get a consistent, meaningful validation error instead of a raw NPE.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/naming/TopicName.java:241
}
if (this.domain == TopicDomain.segment) {
this.completeTopicName = String.format("%s://%s/%s/%s/%s",
domain, tenant, namespacePortion, localName,
String.format("%04x-%04x-%d", segmentRange.start(), segmentRange.end(), segmentId));
} else {
this.completeTopicName = completeTopicName;
}
}
if (StringUtils.isBlank(localName)) {
throw new IllegalArgumentException(String.format("Invalid topic name: %s. Topic local name must not"
+ " be blank.", completeTopicName));
}
this.partitionIndex = getPartitionIndex(localName);
this.namespaceName = NamespaceName.get(tenant, namespacePortion);
} catch (NullPointerException e) {
throw new IllegalArgumentException("Invalid topic name: " + completeTopicName, e);
}
}
public boolean isPersistent() {
return TopicDomain.persistent == domain || TopicDomain.topic == domain || TopicDomain.segment == domain;
}
public boolean isScalable() {
return TopicDomain.topic == domain;
}
public boolean isSegment() {
return TopicDomain.segment == domain;
}
/**
* Get the segment hash range for segment:// topics.
*View on GitHub (pinned to 820761864e)
Solutions
- Log/inspect the exception cause (getCause()) to see the underlying NPE and which segment was missing
- Ensure the input is non-null and follows '<domain>://<tenant>/<namespace>/<local-name>'
- Add an explicit null/format check in your code before calling TopicName.get()
Example fix
// before
TopicName.get(config.getTopic()); // getTopic() may return null
// after
String t = config.getTopic();
if (t == null || !t.contains("://")) { throw new ConfigException("topic must be a full topic URL"); }
TopicName.get(t); Defensive patterns
Strategy: validation
Validate before calling
public static void requireNotNullTopic(String topic) {
java.util.Objects.requireNonNull(topic, "topic name must not be null");
if (!topic.contains("://")) throw new IllegalArgumentException("topic must be a full topic URL: " + topic);
} Type guard
public static boolean isNonNullFullTopic(String s) { return s != null && s.contains("://"); } Try / catch
try {
TopicName tn = TopicName.get(input);
} catch (IllegalArgumentException e) {
Throwable cause = e.getCause(); // NPE shows which parse step failed
log.error("Invalid topic '{}': {}", input, cause == null ? e.getMessage() : cause.toString());
} Prevention
- Null-check topic strings before calling TopicName.get
- Use Objects.requireNonNull with a helpful message at API boundaries
- Inspect getCause() when you see 'Invalid topic name' with no format detail — an NPE cause means a structurally broken name
- Keep test fixtures using real topic names, not nulls
When it happens
Trigger: Calling TopicName.get() / new TopicName(...) with a null or malformed string that causes a NullPointerException during parsing — e.g. null input, or a name that fails the expected 'domain://tenant/namespace/local' structure so an expected part is missing.
Common situations: Passing an unvalidated config value or method argument that is null; a topic name with too few segments causing an array/list index to be missing; test fixtures with placeholder nulls; deserialization producing null topic fields.
Related errors
- Invalid topic name: %s. Topic local name must not be blank.
- V1 topic names (with cluster component) are no longer suppor
- ${topic} is invalid. Expected format: '<domain>://tenant/nam
- ${topic} has blank local topic
- ${topic} is invalid
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/94eae28d6f1d8997.
Report an issue: GitHub.