{"record":{"id":"4bc3506518ece143","repo":"MuntashirAkon/AppManager","slug":"external-directory-unavailable","errorCode":null,"errorMessage":"External directory unavailable.","messagePattern":"External directory unavailable\\.","errorType":"exception","errorClass":"java.lang.IllegalStateException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/servermanager/ServerConfig.java","lineNumber":56,"sourceCode":"    private static final String LOCAL_TOKEN = \"l_token\";\n    private static final SharedPreferences sPreferences = ContextUtils.getContext()\n            .getSharedPreferences(\"server_config\", Context.MODE_PRIVATE);\n\n    @WorkerThread\n    @NoOps\n    public static void init(@NonNull Context context) throws IOException {\n        // Setup paths\n        boolean force = BuildConfig.DEBUG;\n        try {\n            File externalCachePath = FileUtils.getExternalCachePath(context);\n            File externalCacheAmJar = new File(externalCachePath, Constants.JAR_NAME);\n            File externalCacheMainJar = new File(externalCachePath, Constants.MAIN_JAR_NAME);\n            AssetsUtils.copyFile(context, Constants.JAR_NAME, externalCacheAmJar, force);\n            AssetsUtils.copyFile(context, Constants.MAIN_JAR_NAME, externalCacheMainJar, force);\n            FileUtils.chmod644(externalCacheAmJar);\n            FileUtils.chmod644(externalCacheMainJar);\n        } catch (Exception e) {\n            throw new IllegalStateException(\"External directory unavailable.\", e);\n        }\n\n        try {\n            File amPath = getAppManagerStoragePath();\n            File externalAmJar = new File(amPath, Constants.JAR_NAME);\n            File externalMainJar = new File(amPath, Constants.MAIN_JAR_NAME);\n            AssetsUtils.copyFile(context, Constants.JAR_NAME, externalAmJar, force);\n            AssetsUtils.copyFile(context, Constants.MAIN_JAR_NAME, externalMainJar, force);\n            FileUtils.chmod644(externalAmJar);\n            FileUtils.chmod644(externalMainJar);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    @NonNull\n    public static File getAppManagerStoragePath() throws SecurityException {\n        File externalStorage = Environment.getExternalStorageDirectory();","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/servermanager/ServerConfig.java#L38-L74","documentation":"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.","triggerScenarios":"Calling init when context.getExternalCacheDir() (or the resolved externalCachePath) returns null or the copy/chmod throws, e.g. storage unmounted or permissions revoked.","commonSituations":"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.","solutions":["Ensure external storage is available (Environment.getExternalStorageState() == MEDIA_MOUNTED) before calling init","Verify storage permissions (READ/WRITE_EXTERNAL_STORAGE or scoped-storage compliance) are granted","Remount/reattach storage (disable USB file transfer mode) and retry","Unwrap the cause 'e' to see the original failure (null path, IOException from copyFile, chmod failure)"],"exampleFix":"// before\nServerConfig.init(context, false);\n// after\nif (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {\n    ServerConfig.init(context, false);\n} else {\n    throw new IOException(\"External storage not mounted; cannot init server config\");\n}","handlingStrategy":"validation","validationCode":"if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {\n    throw new IOException(\"External storage not mounted\");\n}\nFile dir = context.getExternalCacheDir();\nif (dir == null || !dir.canWrite()) {\n    throw new IOException(\"External cache dir unavailable\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    ServerConfig.init(context, false);\n} catch (IllegalStateException e) {\n    Log.e(TAG, \"Server init failed (storage)\", e.getCause());\n    // prompt user to free/enable storage\n}","preventionTips":["Check Environment.getExternalStorageState() before init","Request and verify storage permissions on legacy Android versions","Handle the USB-file-transfer (storage unmounted) state in UX","Unwrap and log getCause() to distinguish null-path vs copy failures"],"tags":["android","storage","initialization"],"backgroundTag":"missing-env-var","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}