apache/pulsar · error · RestException
getTopicNotFoundErrorMessage(topicName.toString())
Error message
getTopicNotFoundErrorMessage(topicName.toString())
What it means
HTTP 404 thrown by getPropertiesAsync (used by the topic-properties admin API) when getTopicIfExists returns empty, i.e. no persistent topic is loaded/existing under the given name on this broker. The endpoint reads managed-ledger properties, which only exist for an actual PersistentTopic, so a missing topic yields NOT_FOUND with the standard 'topic not found' message.
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/PersistentTopicsBase.java:664
.thenCompose(__ -> {
if (topicName.isPartitioned()) {
return getPropertiesAsync();
}
return pulsar().getBrokerService().fetchPartitionedTopicMetadataAsync(topicName)
.thenCompose(metadata -> {
if (metadata.partitions == 0) {
return getPropertiesAsync();
}
return CompletableFuture.completedFuture(metadata.properties);
});
});
}
private CompletableFuture<Map<String, String>> getPropertiesAsync() {
return pulsar().getBrokerService().getTopicIfExists(topicName.toString())
.thenApply(opt -> {
if (!opt.isPresent()) {
throw new RestException(Status.NOT_FOUND,
getTopicNotFoundErrorMessage(topicName.toString()));
}
return ((PersistentTopic) opt.get()).getManagedLedger().getProperties();
});
}
protected CompletableFuture<Void> internalUpdatePropertiesAsync(boolean authoritative,
Map<String, String> properties) {
if (properties == null || properties.isEmpty()) {
log.warn()
.attr("topic", topicName)
.log("properties is empty, ignore update");
return CompletableFuture.completedFuture(null);
}
return validateTopicOperationAsync(topicName, TopicOperation.UPDATE_METADATA)
.thenCompose(__ -> validateTopicOwnershipAsync(topicName, authoritative))
.thenCompose(__ -> {
if (topicName.isPartitioned()) {View on GitHub (pinned to 820761864e)
Solutions
- Verify the topic exists: `pulsar-admin topics list <namespace>` or `pulsar-admin topics stats`, create it if missing.
- Ensure you query the exact partition name (e.g. topic-partition-0) for persistent topics, or the partitioned parent for its own properties.
- Confirm your client targets the correct cluster/service URL so the lookup/redirect resolves to the owning broker.
- Recreate the topic if it was deleted and properties are needed afterwards.
Example fix
// before GET /admin/v2/persistent/my-tenant/my-ns/my-topic/properties // after (query an existing partition) GET /admin/v2/persistent/my-tenant/my-ns/my-topic-partition-0/properties
Defensive patterns
Strategy: try-catch
Validate before calling
if (!admin.topics().getList(namespace).contains(topic)) {
throw new IllegalStateException("Topic " + topic + " does not exist");
}
Map<String,String> props = admin.topics().getProperties(topic); Try / catch
try {
return admin.topics().getProperties(topic);
} catch (PulsarAdminException.NotFoundException e) {
return Collections.emptyMap();
} Prevention
- Check topic existence with getList or stats before reading properties
- Use the correct partition name for persistent topics
- Route requests to the owning broker/cluster
When it happens
Trigger: GET /admin/v2/persistent/{ns}/{topic}/properties on a topic that does not exist, was already deleted, or is only present as partitioned metadata without the individual partition loaded.
Common situations: Querying properties of a deleted topic; hitting a broker that does not own the topic without redirection (wrong service URL); typo in topic name; topic exists but partitions were never created.
Related errors
- Topic %s does not exist
- Topic %s not found.
- cluster data is required
- Cannot delete non empty namespace
- Local cluster is not part of replicate cluster list
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/aad50f2da36d1b94.
Report an issue: GitHub.