apache/hadoop · error · PathNotFoundException
{}
Error message
{} What it means
FSRegistryOperationsService.delete() first calls fs.exists(dirPath) and throws PathNotFoundException(path) when the registry path is absent. Unlike the ZooKeeper-backed path (CuratorService.zkDelete, documented as 'not an error to delete a path that does not exist'), the FS backend makes deleting a missing path an explicit error. The empty '{}' message is just the registry path passed to the exception constructor.
Source
Thrown at hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/client/impl/FSRegistryOperationsService.java:226
// Only count dirs; the _record files are hidden.
for (int i = 0; i < statArray.length; i++) {
stat = statArray[i];
if (stat.isDirectory()) {
String relativePath = relativize(basePath, stat.getPath().toString());
paths.add(relativePath);
}
}
return paths;
}
@Override
public void delete(String path, boolean recursive)
throws PathNotFoundException, PathIsNotEmptyDirectoryException,
InvalidPathnameException, IOException {
Path dirPath = makePath(path);
if (!fs.exists(dirPath)) {
throw new PathNotFoundException(path);
}
// If recursive == true, or dir is empty, delete.
if (recursive || list(path).isEmpty()) {
fs.delete(makePath(path), true);
return;
}
throw new PathIsNotEmptyDirectoryException(path);
}
@Override
public boolean addWriteAccessor(String id, String pass) throws IOException {
throw new NotImplementedException("Code is not implemented");
}
@Override
public void clearWriteAccessors() {View on GitHub (pinned to 2add963021)
Solutions
- Guard the delete with exists(path) (or stat in try/catch) so absence is handled as success.
- Wrap delete in try-catch and treat PathNotFoundException as 'already gone' for idempotent cleanup.
- Serialize unregister flows (only one owner deletes a given path) to remove the race.
Example fix
// before
registryOperations.delete("/services/worker-1", false); // already unregistered -> PathNotFoundException
// after: idempotent delete
try {
registryOperations.delete("/services/worker-1", false);
} catch (PathNotFoundException e) {
LOG.debug("Path already removed: {}", e.getMessage());
} Defensive patterns
Strategy: validation
Validate before calling
if (registryOperations.exists(path)) {
registryOperations.delete(path, recursive);
} Try / catch
try {
registryOperations.delete(path, recursive);
} catch (PathNotFoundException e) {
// already gone: treat as success for idempotent cleanup
} Prevention
- Remember the delete semantics differ between backends: ZK tolerates missing paths, the FS backend throws.
- Make unregister flows idempotent with an exists() guard or a PathNotFoundException catch.
- Assign a single owner per registry path so concurrent deletes cannot race.
When it happens
Trigger: delete(path, recursive) on a path never created, already deleted, or removed by another client between your check and the call: double-unregister from cleanup code plus a shutdown hook, or retry logic re-running a delete after partial failure.
Common situations: Idempotent cleanup code written against the ZK backend (where absence is tolerated) and reused with the FS backend; racing deregistrations during service restart; tests that delete fixtures twice.
Related errors
- no parent for {}
- Item not found: %s
- Failed to delete ${file}
- Expected {} bytes, but read {}
- Code is not implemented
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/37bb5003c11ac7db.
Report an issue: GitHub.