apache/pulsar · error · RestException
Topic does not exist: ${persistentBase}
Error message
Topic does not exist: ${persistentBase} What it means
HTTP 404 raised during migration when the source regular (persistent) topic named by the path does not exist. Migration transforms an existing regular topic into a scalable one, so the source must exist before the prechecks can run.
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/v2/ScalableTopics.java:331
* watch);</li>
* <li>terminate the old topics so no further v4 writes can land — they become the
* drainable sealed parent segments.</li>
* </ol>
*/
private CompletableFuture<Void> doMigrateToScalableAsync(TopicName scalableName,
TopicName persistentBase, boolean force) {
return resources().getScalableTopicMetadataAsync(scalableName).thenCompose(existing -> {
if (existing.isPresent()) {
throw new RestException(Response.Status.CONFLICT,
"Topic is already scalable: " + scalableName);
}
return pulsar().getNamespaceService().checkTopicExistsAsync(persistentBase);
}).thenCompose(existsInfo -> {
boolean exists = existsInfo.isExists();
int partitions = existsInfo.getPartitions();
existsInfo.recycle();
if (!exists) {
throw new RestException(Response.Status.NOT_FOUND,
"Topic does not exist: " + persistentBase);
}
CompletableFuture<Void> precheck = force
? CompletableFuture.completedFuture(null)
: checkNoLegacyConnectionsAsync(persistentBase, partitions);
return precheck.thenApply(__ -> partitions);
}).thenCompose(partitions -> {
ScalableTopicMetadata metadata =
ScalableTopicController.createMigratedMetadata(persistentBase, partitions,
pulsar().getConfiguration().getScalableTopicEntryBucketBudget(),
pulsar().getConfiguration().getScalableTopicEntryBucketMaxPerSegment());
return createMigratedChildTopicsAsync(scalableName, metadata)
.thenCompose(__ -> resources().createScalableTopicAsync(scalableName, metadata))
.thenCompose(__ -> terminateLegacyTopicsAsync(persistentBase, partitions));
});
}
/**View on GitHub (pinned to 820761864e)
Solutions
- Verify the topic exists with GET /admin/v2/persistent/{tenant}/{namespace}/{topic} (or topics list) before migrating.
- Correct the topic name, partition suffix, tenant, or namespace in the migration call.
- Create the topic first if it never existed, or skip migration entirely for non-existent sources.
Example fix
// before
await admin.scalableTopics().migrateToScalable(tenant, ns, 'my-topc');
// after
const exists = await admin.topics().getStatsAsync('persistent://tn/ns/my-topic');
await admin.scalableTopics().migrateToScalable(tenant, ns, 'my-topic'); Defensive patterns
Strategy: validation
Validate before calling
try {
await admin.topics().getStatsAsync(`persistent://${tenant}/${ns}/${topic}`);
} catch (e) {
if (e.status === 404) throw new Error(`Source topic ${topic} does not exist; fix name or skip`);
throw e;
} Type guard
const topicExists = async (tn) => { try { await admin.topics().getStatsAsync(tn); return true; } catch (e) { return e.status !== 404; } }; Try / catch
try {
await admin.scalableTopics().migrateToScalable(tenant, ns, topic);
} catch (e) {
if (e.status === 404) { /* verify source topic name/existence before retry */ }
throw e;
} Prevention
- Resolve topic names from the namespace's topic list rather than hand-typing them.
- Verify tenant/namespace/topic spelling and partition suffixes in migration scripts.
- Skip non-existent source topics explicitly instead of letting the migration fail.
When it happens
Trigger: Calling POST /admin/v2/scalable-topics/{tenant}/{namespace}/{topic}/migrate when the underlying persistent topic was never created, was deleted, or the name is misspelled/mis-partitioned (e.g. wrong partition index).
Common situations: Typos in topic names in migration scripts; migrating a topic whose producers never connected (auto-creation disabled so nothing materialized); migrating after a cleanup job deleted the topic; wrong namespace/tenant in the URL.
Related errors
- Scalable topic not found: ${tn}
- Topic is already scalable: ${scalableName}
- ${legacy} legacy v4 client connection(s) still attached to $
- Segment topic not found: ${segmentTopic}
- Segment topic not loaded: ${segmentTopic}
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/ed5c68434eb461e9.
Report an issue: GitHub.