MuntashirAkon/AppManager · error · IOException

+ path + is not a file.

Error message

+ path + is not a file.

What it means

VirtualFileSystem.newInputStream(path) throws IOException("path is not a file.") when the resolved node exists but Node.isFile() is false — typically the path points to a directory. Input streams can only be opened on regular file nodes in this VFS.

Source

Thrown at app/src/main/java/io/github/muntashirakon/io/fs/VirtualFileSystem.java:971

    }

    public boolean createLink(String link, String target, boolean soft) {
        checkMounted();
        return false;
    }

    /* I/O APIs */
    @NonNull
    public FileInputStream newInputStream(String path) throws IOException {
        if (!checkAccess(path, OsConstants.R_OK)) {
            throw new IOException(path + " is inaccessible.");
        }
        Node<?> targetNode = getNode(path);
        if (targetNode == null) {
            throw new FileNotFoundException(path + " does not exist.");
        }
        if (!targetNode.isFile()) {
            throw new IOException(path + " is not a file.");
        }
        return new FileInputStream(getCachedFile(targetNode, false));
    }

    @NonNull
    public FileOutputStream newOutputStream(String path, boolean append) throws IOException {
        if (!checkAccess(path, OsConstants.W_OK)) {
            throw new IOException(path + " is inaccessible.");
        }
        Node<?> targetNode = getNode(path);
        if (targetNode == null) {
            throw new FileNotFoundException(path + " does not exist.");
        }
        if (!targetNode.isFile()) {
            throw new IOException(path + " is not a file.");
        }
        return new FileOutputStream(getCachedFile(targetNode, true), append);
    }

View on GitHub (pinned to 0152f468fc)

Solutions

  1. Check node type before reading: only call newInputStream on paths known to be files (e.g. via VFS metadata/ls)
  2. If a directory was intended, list its children and pick the concrete file to open
  3. Fix path construction so it ends in a file name, not a directory

Example fix

// before
FileInputStream in = vfs.newInputStream(selectedPath); // selectedPath may be a dir
// after
if (vfs.isDirectory(selectedPath)) {
    throw new IllegalArgumentException("Select a file, not a directory: " + selectedPath);
}
FileInputStream in = vfs.newInputStream(selectedPath);
Defensive patterns

Strategy: validation

Validate before calling

if (vfs.isDirectory(path)) throw new IllegalArgumentException("Expected a file: " + path);

Try / catch

try {
    FileInputStream in = vfs.newInputStream(path);
} catch (IOException e) {
    if (e.getMessage() != null && e.getMessage().endsWith("is not a file.")) {
        // treat as directory: list children instead
    }
}

Prevention

When it happens

Trigger: Calling newInputStream() on a directory path; passing a path that resolves to a directory-like or special node (e.g. a virtual root or folder entry) instead of a leaf file.

Common situations: User selects a folder in a file picker and the app tries to read it; a config path mistakenly points at a directory expecting auto-resolution to a default file inside; path built by concatenating a prefix that already includes a directory name.

Related errors


AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12). Data as JSON: /api/errors/440b87aa2b7ef8de. Report an issue: GitHub.