apache/hadoop · error · IllegalArgumentException

PathHandle only available for files

Error message

PathHandle only available for files

What it means

Thrown by RawLocalFileSystem.createPathHandle (the hook behind FileSystem.getPathHandle(FileStatus, HandleOpt...)) when the supplied FileStatus refers to a directory or a symbolic link. A PathHandle is an immutable reference to the *content* of a regular file, so directories and links have no meaningful handle in the local FileSystem implementation. The library fails fast with IllegalArgumentException rather than returning a handle that could never be resolved.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/fs/RawLocalFileSystem.java:1233

          pathToFile(p).toPath(), BasicFileAttributeView.class);
      FileTime fmtime = (mtime >= 0) ? FileTime.fromMillis(mtime) : null;
      FileTime fatime = (atime >= 0) ? FileTime.fromMillis(atime) : null;
      view.setTimes(fmtime, fatime, null);
    } catch (NoSuchFileException e) {
      throw new FileNotFoundException("File " + p + " does not exist");
    }
  }

  /**
   * Hook to implement support for {@link PathHandle} operations.
   * @param stat Referent in the target FileSystem
   * @param opts Constraints that determine the validity of the
   *            {@link PathHandle} reference.
   */
  protected PathHandle createPathHandle(FileStatus stat,
      Options.HandleOpt... opts) {
    if (stat.isDirectory() || stat.isSymlink()) {
      throw new IllegalArgumentException("PathHandle only available for files");
    }
    String authority = stat.getPath().toUri().getAuthority();
    if (authority != null && !authority.equals("file://")) {
      throw new IllegalArgumentException("Wrong FileSystem: " + stat.getPath());
    }
    Options.HandleOpt.Data data =
        Options.HandleOpt.getOpt(Options.HandleOpt.Data.class, opts)
            .orElse(Options.HandleOpt.changed(false));
    Options.HandleOpt.Location loc =
        Options.HandleOpt.getOpt(Options.HandleOpt.Location.class, opts)
            .orElse(Options.HandleOpt.moved(false));
    if (loc.allowChange()) {
      throw new UnsupportedOperationException("Tracking file movement in " +
          "basic FileSystem is not supported");
    }
    final Path p = stat.getPath();
    final Optional<Long> mtime = !data.allowChange()
        ? Optional.of(stat.getModificationTime())

View on GitHub (pinned to 2add963021)

Solutions

  1. Filter to regular files first: only call getPathHandle when stat.isFile() && !stat.isSymlink()
  2. If the referent is a symlink to a file, resolve the link target (fs.resolvePath/stat via FileContext) and build the handle from the target's FileStatus
  3. Catch IllegalArgumentException at the call site and skip the entry when iterating heterogeneous listings

Example fix

// before
FileStatus st = localFs.getFileStatus(p);
PathHandle h = localFs.getPathHandle(st);

// after
FileStatus st = localFs.getFileStatus(p);
if (st.isDirectory() || st.isSymlink()) {
  throw new IllegalArgumentException("PathHandle requires a regular file: " + p);
}
PathHandle h = localFs.getPathHandle(st);
Defensive patterns

Strategy: validation

Validate before calling

FileStatus st = fs.getFileStatus(p);
if (st.isDirectory() || st.isSymlink()) {
  // skip or fail before asking for a handle
  throw new IllegalArgumentException("PathHandle requires a regular file: " + p);
}
PathHandle h = fs.getPathHandle(st, opts);

Try / catch

try {
  PathHandle h = fs.getPathHandle(stat);
} catch (IllegalArgumentException e) {
  // message: "PathHandle only available for files" -> wrong referent kind
  log.warn("Skipping non-file: {}", stat.getPath());
}

Prevention

When it happens

Trigger: Calling localFs.getPathHandle(stat, opts) where stat was obtained via getFileStatus()/listStatus() on a directory, or on a symlink (stat.isSymlink() == true). Also hit when code takes FileStatus from listStatus() of a directory tree and blindly calls getPathHandle() on each entry.

Common situations: Batch tools iterating a directory and requesting handles for every entry without filtering; passing a link status returned by getFileLinkStatus(); test code that uses a temp directory instead of a temp file.

Related errors


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