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

  1. Guard the delete with exists(path) (or stat in try/catch) so absence is handled as success.
  2. Wrap delete in try-catch and treat PathNotFoundException as 'already gone' for idempotent cleanup.
  3. 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

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


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/37bb5003c11ac7db. Report an issue: GitHub.