{"record":{"id":"22ee9aedac79c052","repo":"MuntashirAkon/AppManager","slug":"couldn-t-find-any-writable-obb-dir","errorCode":null,"errorMessage":"Couldn't find any writable Obb dir","messagePattern":"Couldn't find any writable Obb dir","errorType":"exception","errorClass":"FileNotFoundException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/apk/ApkUtils.java","lineNumber":312,"sourceCode":"                .findOrCreateDirectory(\"obb\")\n                .findOrCreateDirectory(packageName);\n        return Paths.get(obbDir.getUri());\n    }\n\n    @NonNull\n    public static Path getWritableExternalDirectory(@UserIdInt int userId) throws FileNotFoundException {\n        // Get the first writable external storage directory\n        OsEnvironment.UserEnvironment userEnvironment = OsEnvironment.getUserEnvironment(userId);\n        Path[] extDirs = userEnvironment.getExternalDirs();\n        Path writableExtDir = null;\n        for (Path extDir : extDirs) {\n            if (extDir.canWrite() || Objects.requireNonNull(extDir.getFilePath()).startsWith(\"/storage/emulated\")) {\n                writableExtDir = extDir;\n                break;\n            }\n        }\n        if (writableExtDir == null) {\n            throw new FileNotFoundException(\"Couldn't find any writable Obb dir\");\n        }\n        return writableExtDir;\n    }\n\n    public static int getDensityFromName(@Nullable String densityName) {\n        Integer density = StaticDataset.DENSITY_NAME_TO_DENSITY.get(densityName);\n        if (density == null) {\n            throw new IllegalArgumentException(\"Unknown density \" + densityName);\n        }\n        return density;\n    }\n\n    @NonNull\n    private static ByteBuffer getAndroidManifestFromApk(\n            @NonNull List<CentralDirectoryRecord> cdRecords, @NonNull DataSource lhfSection)\n            throws IOException, ApkFormatException, ZipFormatException {\n        CentralDirectoryRecord androidManifestCdRecord = findCdRecord(cdRecords, MANIFEST_FILE);\n        if (androidManifestCdRecord == null) {","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/apk/ApkUtils.java#L294-L330","documentation":"getWritableExternalDirectory iterates candidate external storage directories and throws FileNotFoundException when none is writable (or on /storage/emulated). It is used by obbDir() to locate a directory where OBB files can be written; without a writable external dir, OBB installation cannot proceed.","triggerScenarios":"Calling ApkUtils.obbDir() when every enumerated external directory is read-only or not under /storage/emulated — e.g. fully adopted storage, restricted storage permissions, or scoped-storage restrictions on Android 11+ where no writable external dir is found.","commonSituations":"Running on devices with no SD card and denied MANAGE_EXTERNAL_STORAGE/READ_WRITE permissions, Android 11+ scoped storage restricting OBB paths, emulators with unusual storage layouts, or work-profile/restricted users.","solutions":["Grant storage permissions (MANAGE_EXTERNAL_STORAGE on Android 11+, or READ/WRITE_EXTERNAL_STORAGE with legacy storage) before calling obbDir().","Check that at least one external storage volume is mounted and writable via Environment.getExternalStorageState().","Fall back to app-private storage (context.getExternalFilesDirs or getObbDirs) and handle the exception by copying OBB data there.","Wrap obbDir() in try-catch for FileNotFoundException and surface a user-facing 'no writable storage' message."],"exampleFix":"// before\nFile obbDir = ApkUtils.obbDir();\n// after\nFile obbDir;\ntry {\n    obbDir = ApkUtils.obbDir();\n} catch (FileNotFoundException e) {\n    obbDir = context.getExternalFilesDir(null); // fallback\n}","handlingStrategy":"fallback","validationCode":"boolean hasWritable = Arrays.stream(context.getExternalFilesDirs(null))\n        .anyMatch(d -> d != null && d.canWrite());\nif (!hasWritable) requestStoragePermissionsOrAbort();","typeGuard":null,"tryCatchPattern":"try {\n    File obbDir = ApkUtils.obbDir();\n} catch (FileNotFoundException e) {\n    File fallback = context.getExternalFilesDir(null);\n}","preventionTips":["Request MANAGE_EXTERNAL_STORAGE / legacy storage permissions before OBB operations.","Check Environment.getExternalStorageState() equals MEDIA_MOUNTED before use.","Design for scoped storage (Android 11+): prefer app-specific dirs over shared external storage.","Test on devices with adopted storage and no SD card."],"tags":["android","storage","filesystem","obb"],"backgroundTag":"file-not-found","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}