apache/hadoop · error · PathNotFoundException

no parent for {}

Error message

no parent for {}

What it means

Thrown by the filesystem-backed registry implementation (FSRegistryOperationsService) from mknode when createParents is false and the parent of the target registry path exists in the filesystem but is a file rather than a directory. In this backend a bound ServiceRecord is stored as a file (see formatDataPath), so a record occupying the parent path makes it impossible to create directories beneath it. The message 'no parent for <path>' therefore means 'the parent exists but is not usable as a directory', not merely 'parent missing'.

Source

Thrown at hadoop-common-project/hadoop-registry/src/main/java/org/apache/hadoop/registry/client/impl/FSRegistryOperationsService.java:127

      fs.getFileStatus(registryPath);
      return false;
    } catch (FileNotFoundException e) {
    }

    if (createParents) {
      // By default, mkdirs creates any parent dirs it needs
      fs.mkdirs(registryPath);
    } else {
      FileStatus parentStatus = null;

      if (registryPath.getParent() != null) {
        parentStatus = fs.getFileStatus(registryPath.getParent());
      }

      if (registryPath.getParent() == null || parentStatus.isDirectory()) {
        fs.mkdirs(registryPath);
      } else {
        throw new PathNotFoundException("no parent for " + path);
      }
    }
    return true;
  }

  @Override
  public void bind(String path, ServiceRecord record, int flags)
      throws PathNotFoundException, FileAlreadyExistsException,
      InvalidPathnameException, IOException {

    // Preserve same overwrite semantics as ZK implementation
    Preconditions.checkArgument(record != null, "null record");
    RegistryTypeUtils.validateServiceRecord(path, record);

    Path dataPath = formatDataPath(path);
    Boolean overwrite = ((flags & BindFlags.OVERWRITE) != 0);
    if (fs.exists(dataPath) && !overwrite) {
      throw new FileAlreadyExistsException();

View on GitHub (pinned to 2add963021)

Solutions

  1. Check stat()/list() on the parent path: if it is a record (resolvable) rather than a container, delete or move the conflicting record, then retry mknode.
  2. Call mknode with createParents=true for the branch that simply runs fs.mkdirs, so missing ancestors are created (note this still cannot succeed if a file occupies an ancestor path).
  3. Fix the layout convention: bind records only at leaf paths and mknode container directories before binding children beneath them.
  4. Catch PathNotFoundException around mknode and surface an application-level 'path conflict' error naming the parent.

Example fix

// before
registryOperations.bind("/services/api", record);      // creates record file at /services/api
registryOperations.mknode("/services/api/child", false); // parent is a file -> PathNotFoundException("no parent for /services/api/child")

// after: create the container directory first, bind records at leaves only
registryOperations.mknode("/services/api", true);
registryOperations.bind("/services/api/instance-1", record, RegistryOperations.BIND_OVERWRITE);
Defensive patterns

Strategy: validation

Validate before calling

// before mknode, confirm the parent is resolvable as a container, not a record
String parent = RegistryPathUtils.parentOf(path);
if (!registryOperations.exists(parent)) {
  registryOperations.mknode(parent, true); // create missing ancestors first
} else {
  try {
    registryOperations.resolve(parent);
    // parent holds a ServiceRecord file: creating children beneath it will fail
    throw new IllegalStateException("Parent " + parent + " is bound as a record, not a container");
  } catch (NoRecordException e) {
    // good: parent is a plain directory
  }
}

Try / catch

try {
  registryOperations.mknode(path, false);
} catch (PathNotFoundException e) {
  // parent missing entirely, or parent is a record file ("no parent for ...")
  // decide: create ancestors, or remove/relocate the conflicting record
}

Prevention

When it happens

Trigger: Calling RegistryOperations.mknode(path, false) when fs.getFileStatus(registryPath.getParent()) succeeds but parentStatus.isDirectory() is false. Typical sequence: bind() a ServiceRecord at /services/api (creates a record file), then mknode("/services/api/child", false). Also hit when a stale record file left in the registry root occupies a path your code expects to be a container directory.

Common situations: Switching from the ZooKeeper-backed registry to the FS-backed backend where record-as-file semantics are more visible; creating child entries under a path previously bound as a record; leftover record files in the HDFS registry root after partial cleanup.

Related errors


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