MuntashirAkon/AppManager · error · java.lang.IllegalStateException

External directory unavailable.

Error message

External directory unavailable.

What it means

ServerConfig.init copies the AM and main JARs from app assets to the external cache directory (and chmods them). Any failure in that block — typically because external storage is unavailable — is rethrown as an IllegalStateException so callers get a clear 'external directory unavailable' signal.

Source

Thrown at app/src/main/java/io/github/muntashirakon/AppManager/servermanager/ServerConfig.java:56

    private static final String LOCAL_TOKEN = "l_token";
    private static final SharedPreferences sPreferences = ContextUtils.getContext()
            .getSharedPreferences("server_config", Context.MODE_PRIVATE);

    @WorkerThread
    @NoOps
    public static void init(@NonNull Context context) throws IOException {
        // Setup paths
        boolean force = BuildConfig.DEBUG;
        try {
            File externalCachePath = FileUtils.getExternalCachePath(context);
            File externalCacheAmJar = new File(externalCachePath, Constants.JAR_NAME);
            File externalCacheMainJar = new File(externalCachePath, Constants.MAIN_JAR_NAME);
            AssetsUtils.copyFile(context, Constants.JAR_NAME, externalCacheAmJar, force);
            AssetsUtils.copyFile(context, Constants.MAIN_JAR_NAME, externalCacheMainJar, force);
            FileUtils.chmod644(externalCacheAmJar);
            FileUtils.chmod644(externalCacheMainJar);
        } catch (Exception e) {
            throw new IllegalStateException("External directory unavailable.", e);
        }

        try {
            File amPath = getAppManagerStoragePath();
            File externalAmJar = new File(amPath, Constants.JAR_NAME);
            File externalMainJar = new File(amPath, Constants.MAIN_JAR_NAME);
            AssetsUtils.copyFile(context, Constants.JAR_NAME, externalAmJar, force);
            AssetsUtils.copyFile(context, Constants.MAIN_JAR_NAME, externalMainJar, force);
            FileUtils.chmod644(externalAmJar);
            FileUtils.chmod644(externalMainJar);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @NonNull
    public static File getAppManagerStoragePath() throws SecurityException {
        File externalStorage = Environment.getExternalStorageDirectory();

View on GitHub (pinned to 0152f468fc)

Solutions

  1. Ensure external storage is available (Environment.getExternalStorageState() == MEDIA_MOUNTED) before calling init
  2. Verify storage permissions (READ/WRITE_EXTERNAL_STORAGE or scoped-storage compliance) are granted
  3. Remount/reattach storage (disable USB file transfer mode) and retry
  4. Unwrap the cause 'e' to see the original failure (null path, IOException from copyFile, chmod failure)

Example fix

// before
ServerConfig.init(context, false);
// after
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
    ServerConfig.init(context, false);
} else {
    throw new IOException("External storage not mounted; cannot init server config");
}
Defensive patterns

Strategy: validation

Validate before calling

if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
    throw new IOException("External storage not mounted");
}
File dir = context.getExternalCacheDir();
if (dir == null || !dir.canWrite()) {
    throw new IOException("External cache dir unavailable");
}

Try / catch

try {
    ServerConfig.init(context, false);
} catch (IllegalStateException e) {
    Log.e(TAG, "Server init failed (storage)", e.getCause());
    // prompt user to free/enable storage
}

Prevention

When it happens

Trigger: Calling init when context.getExternalCacheDir() (or the resolved externalCachePath) returns null or the copy/chmod throws, e.g. storage unmounted or permissions revoked.

Common situations: Device in USB mass-storage/MTP mode where external storage is unmounted, scoped-storage restrictions on newer Android versions, or first launch before storage permission granted.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


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