apache/pulsar · error · MetadataStoreException.NotFoundException
path %s not found.
Error message
path %s not found.
What it means
storeDelete performs a transactional read of the path and parses it as MetaValue. If no record exists under the path (null value / null parse result), it throws MetadataStoreException.NotFoundException with 'path %s not found.'. Callers using delete(path, expectedVersion-style API) hit this when deleting a key that was never created or was already deleted.
Source
Thrown at pulsar-metadata/src/main/java/org/apache/pulsar/metadata/impl/RocksdbMetadataStore.java:570
} finally {
dbStateLock.readLock().unlock();
}
}
@Override
protected CompletableFuture<Void> storeDelete(String path, Optional<Long> expectedVersion, Set<Option> opts) {
log.debug().attr("path", path).attr("instanceId", instanceId).log("storeDelete");
try {
dbStateLock.readLock().lock();
if (isClosed()) {
return alreadyClosedFailedFuture();
}
try (Transaction transaction = db.beginTransaction(writeOptions)) {
byte[] pathBytes = toBytes(path);
byte[] oldValueData = transaction.getForUpdate(optionDontCache, pathBytes, true);
MetaValue metaValue = MetaValue.parse(oldValueData);
if (metaValue == null) {
throw new MetadataStoreException.NotFoundException(String.format("path %s not found.", path));
}
if (expectedVersion.isPresent() && !expectedVersion.get().equals(metaValue.getVersion())) {
throw new MetadataStoreException.BadVersionException(
String.format("Version mismatch, actual=%s, expect=%s", metaValue.getVersion(),
expectedVersion.get()));
}
transaction.delete(pathBytes);
transaction.commit();
receivedNotification(new Notification(NotificationType.Deleted, path));
notifyParentChildrenChanged(path);
return CompletableFuture.completedFuture(null);
}
} catch (Throwable e) {
log.debug().attr("path", path).exception(e).log("error in storeDelete");
return FutureUtil.failedFuture(MetadataStoreException.wrap(e));
} finally {
dbStateLock.readLock().unlock();
}View on GitHub (pinned to 820761864e)
Solutions
- Check existence with store.exists(path) before deleting if absence is acceptable, and ignore NotFoundException.
- Catch MetadataStoreException.NotFoundException and treat as success for idempotent delete semantics.
- Log the path and verify against the producing code why the record is missing.
- Use put-with-version or notifications to coordinate delete races between instances.
Example fix
// before
store.delete(path).join();
// after
try {
store.delete(path).join();
} catch (CompletionException e) {
if (!(e.getCause() instanceof MetadataStoreException.NotFoundException)) throw e;
// already gone — idempotent
} Defensive patterns
Strategy: try-catch
Validate before calling
// check existence before delete boolean exists = store.exists(path).get();
Try / catch
try {
store.delete(path).join();
} catch (CompletionException e) {
if (e.getCause() instanceof MetadataStoreException.NotFoundException) {
// treat as already-deleted (idempotent)
} else throw e;
} Prevention
- Design deletes to be idempotent
- Check exists() when absence is meaningful for your flow
- Coordinate delete races via notifications or a single writer
When it happens
Trigger: Calling storeDelete (via MetadataStore.delete) for a path that does not exist in the RocksDB store, or that was already deleted (possibly by another instance/notification).
Common situations: Race between two consumers both deleting the same znode-like path; application logic assuming existence; cleanup job running twice; typo'd path.
Understand the failure class
Background: "path not found", "No such file or directory", "Directory does not exist": when a library can't resolve the path you gave it — this error's family across 53 libraries.
Related errors
- Timeout during managed ledger delete operation
- NamespaceIsolationPolicies for cluster ${cluster} does not e
- Cannot find NamespaceIsolationPolicy ${policyName} for clust
- Tenant not found
- Namespace does not exist
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/08229052c10bd941.
Report an issue: GitHub.