MuntashirAkon/AppManager · error · FileNotFoundException

No available shared storage found.

Error message

No available shared storage found.

What it means

After iterating the extDirs array, getBestExternalDataSubdir throws FileNotFoundException("No available shared storage found.") when no entry passed the usability checks. Each candidate is logged with a reason (e.g. '<path>: not mounted (unmounted)') and that last reason becomes the exception message when present. Unlike error 410 the array was non-null — the directories exist but none is mounted/usable.

Source

Thrown at app/src/main/java/io/github/muntashirakon/AppManager/utils/FileUtils.java:214

            if (!(extDir.exists() || extDir.mkdirs())) {
                // Try to recreate this with root
                if (RunnerUtils.isRootGiven() && forceCreateExternalDataSubDir(extDir)) {
                    Log.i(TAG, "Root created %s", extDir);
                    return extDir;
                }
                lastReason = extDir + ": permission denied.";
                Log.w(TAG, "Could not use %s.", extDir);
                continue;
            }
            String storageState = Environment.getExternalStorageState(extDir);
            if (!Objects.equals(storageState, Environment.MEDIA_MOUNTED)) {
                lastReason = extDir + ": not mounted (" + storageState + ")";
                Log.w(TAG, "Path %s not mounted. State: %s", extDir, storageState);
                continue;
            }
            return extDir;
        }
        throw new FileNotFoundException(lastReason != null ? lastReason : "No available shared storage found.");
    }

    public static boolean forceCreateExternalDataSubDir(@NonNull File dir) {
        File parentFile = Objects.requireNonNull(dir.getParentFile());
        String parent = parentFile.getAbsolutePath();
        String target = dir.getAbsolutePath();
        String chownTarget;
        boolean createParent = !parentFile.exists();
        if (createParent) {
            // Some rooted Android ROMs cannot create the package directory under Android/data.
            int uid = Process.myUid();
            chownTarget = uid + ":" + uid;
        } else {
            try {
                StructStat parentStat = Os.stat(parent);
                chownTarget = parentStat.st_uid + ":" + parentStat.st_gid;
            } catch (ErrnoException e) {
                // Fallback to shell

View on GitHub (pinned to 0152f468fc)

Solutions

  1. Catch FileNotFoundException and fall back to internal storage (context.getCacheDir())
  2. Log/inspect the exception message — it contains the exact path and Environment state that failed
  3. Check Environment.getExternalStorageState() for each candidate dir before use
  4. Prompt the user to mount/remount the storage volume or reinsert the SD card

Example fix

// before
File extDir = FileUtils.getBestExternalDataSubdir(extDirs);
// after
try {
    extDir = FileUtils.getBestExternalDataSubdir(extDirs);
} catch (FileNotFoundException e) {
    Log.w(TAG, "External storage unavailable: " + e.getMessage());
    extDir = context.getCacheDir();
}
Defensive patterns

Strategy: fallback

Validate before calling

for (File d : extDirs) {
    if (d != null && Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(d))) {
        // usable dir found
    }
}

Type guard

boolean isMounted(File dir) {
    return dir != null && Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(dir));
}

Try / catch

try {
    dir = FileUtils.getBestExternalDataSubdir(extDirs);
} catch (FileNotFoundException e) {
    Log.w(TAG, "No usable external storage: " + e.getMessage());
    dir = context.getCacheDir();
}

Prevention

When it happens

Trigger: Calling getExternalCachePath/getBestExternalDataSubdir when every entry in getExternalFilesDirs(...) is null or whose Environment.getExternalStorageState(dir) is not Environment.MEDIA_MOUNTED (e.g. 'unmounted', 'removed', 'shared' while USB mass-storage is active).

Common situations: SD card ejected or unmounted while app uses it; device connected in USB mass-storage/MTP mode exposing the volume; corrupted volumes reported as unmounted; emulator snapshots with detached virtual SD card.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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