MuntashirAkon/AppManager · error · ErrnoException

EBADF

EBADF

Error message

Supplied path is not a Linux path.

What it means

Paths.chmod wraps ExtendedFile.setMode and requires the Path to be backed by a real Linux (ext4/FUSE) file via path.getFile(). When the Path is not Linux-backed (e.g. a SAF/ContentProvider document or virtual filesystem node), getFile() returns null and an ErrnoException with EBADF is thrown.

Source

Thrown at app/src/main/java/io/github/muntashirakon/io/Paths.java:557

            // Other types of files aren't supported
            return 0;
        }
        long length = 0;
        Path[] files = root.listFiles();
        for (Path file : files) {
            if (ThreadUtils.isInterrupted()) {
                // Size could be too long
                return length;
            }
            length += size(file);
        }
        return length;
    }

    public static void chmod(@NonNull Path path, int mode) throws ErrnoException {
        ExtendedFile file = path.getFile();
        if (file == null) {
            throw new ErrnoException("Supplied path is not a Linux path.", OsConstants.EBADF);
        }
        file.setMode(mode);
    }

    public static void chown(@NonNull Path path, int uid, int gid) throws ErrnoException {
        ExtendedFile file = path.getFile();
        if (file == null) {
            throw new ErrnoException("Supplied path is not a Linux path.", OsConstants.EBADF);
        }
        file.setUidGid(uid, gid);
    }

    /**
     * Set owner and mode of given path.
     *
     * @param mode to apply through {@code chmod}
     * @param uid  to apply through {@code chown}, or -1 to leave unchanged
     * @param gid  to apply through {@code chown}, or -1 to leave unchanged

View on GitHub (pinned to 0152f468fc)

Solutions

  1. Verify the path is Linux-backed (path.getFile() != null) before calling chmod.
  2. Restrict permission changes to files under real filesystem locations (e.g. app-specific or /storage paths), not content:// documents.
  3. For SAF documents, skip chmod or use the documents-contract APIs that support flags instead.
  4. Catch the ErrnoException with code EBADF and surface a clear 'operation not supported on this path type' message.

Example fix

// before
Paths.chmod(path, mode);
// after
ExtendedFile f = path.getFile();
if (f == null) throw new UnsupportedOperationException("Not a Linux path: " + path);
Paths.chmod(path, mode);
Defensive patterns

Strategy: type-guard

Validate before calling

boolean canChmod = path.getFile() != null;

Type guard

static boolean isLinuxPath(Path p) { return p != null && p.getFile() != null; }

Try / catch

try {
    Paths.chmod(path, mode);
} catch (ErrnoException e) {
    if (e.code == OsConstants.EBADF) {
        // not a Linux path: skip or warn
    } else throw e;
}

Prevention

When it happens

Trigger: Calling Paths.chmod(path, mode) (directly or via Path.setPermissions) on a Path whose underlying file is a SAF document, a content:// Uri, or any non-ExtendedFile backing where Path.getFile() returns null.

Common situations: Trying to set permissions on a file picked through the Storage Access Framework or on a virtual/mounted node; code assuming all Paths are filesystem-backed after migrating from java.io.File.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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