{"record":{"id":"0ca1e439b859c6f0","repo":"TeamNewPipe/NewPipe","slug":"no-write-permissions-on","errorCode":null,"errorMessage":"No write permissions on {}","messagePattern":"No write permissions on (.+?)","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"warning","filePath":"app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java","lineNumber":242,"sourceCode":"        // revoke permissions on the old save path (required for SAF only)\n        final Context context = requireContext();\n\n        forgetSAFTree(context, defaultPreferences.getString(key, \"\"));\n\n        if (!FilePickerActivityHelper.isOwnFileUri(context, uri)) {\n            // steps to acquire the selected path:\n            //     1. acquire permissions on the new save path\n            //     2. save the new path, if step(2) was successful\n            try {\n                context.grantUriPermission(context.getPackageName(), uri,\n                        StoredDirectoryHelper.PERMISSION_FLAGS);\n\n                final StoredDirectoryHelper mainStorage =\n                        new StoredDirectoryHelper(context, uri, null);\n                Log.i(TAG, \"Acquiring tree success from \" + uri.toString());\n\n                if (!mainStorage.canWrite()) {\n                    throw new IOException(\"No write permissions on \" + uri.toString());\n                }\n            } catch (final IOException err) {\n                Log.e(TAG, \"Error acquiring tree from \" + uri.toString(), err);\n                showMessageDialog(R.string.general_error, R.string.no_available_dir);\n                return;\n            }\n        } else {\n            final File target = Utils.getFileForUri(uri);\n            if (!target.canWrite()) {\n                showMessageDialog(R.string.download_to_sdcard_error_title,\n                        R.string.download_to_sdcard_error_message);\n                return;\n            }\n            uri = Uri.fromFile(target);\n        }\n\n        defaultPreferences.edit().putString(key, uri.toString()).apply();\n        updatePreferencesSummary();","sourceCodeStart":224,"sourceCodeEnd":260,"githubUrl":"https://github.com/TeamNewPipe/NewPipe/blob/9e8be091560a69f35d44bd252eb00bc7911c977b/app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java#L224-L260","documentation":"Thrown by DownloadSettingsFragment when the user-selected Storage Access Framework (SAF) tree URI, after being granted URI permission and wrapped in a StoredDirectoryHelper, reports canWrite() == false. The fragment treats this as an IOException, logs it, and shows a 'no available directory' dialog. The message includes the offending URI.","triggerScenarios":"In the SAF picker callback (onActivityResult path), the chosen directory URI is granted permission and a StoredDirectoryHelper is constructed for it, but mainStorage.canWrite() returns false. This happens when the SAF permission grant did not actually confer write access, or the selected location is read-only.","commonSituations":"User picks a directory on external/removable storage that the app cannot write to (e.g. a read-only SD card partition, a cloud provider root via SAF, or a directory the system did not grant persistable URI permission for), the SAF permission was not persisted across restarts, or the chosen tree is on a storage volume not mounted as writable. Also when the URI refers to a location whose underlying filesystem is read-only.","solutions":["Pick a different directory the app can actually write to (e.g. internal storage or a writable SD card partition).","Ensure takePersistableUriPermission is called for the granted URI so permission survives restarts.","Verify the storage volume is mounted and writable before selecting it.","If using an SD card, confirm the card is not read-only or corrupted.","On older Android versions targeting SD card writing, use the legacy file-based path instead of SAF where applicable."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"context.grantUriPermission(context.getPackageName(), uri, StoredDirectoryHelper.PERMISSION_FLAGS);\nfinal StoredDirectoryHelper mainStorage = new StoredDirectoryHelper(context, uri, null);\nif (!mainStorage.canWrite()) {\n    // show error dialog; do not persist this path\n}","typeGuard":null,"tryCatchPattern":"try {\n    final StoredDirectoryHelper mainStorage = new StoredDirectoryHelper(context, uri, null);\n    if (!mainStorage.canWrite()) {\n        throw new IOException(\"No write permissions on \" + uri.toString());\n    }\n} catch (final IOException err) {\n    showMessageDialog(R.string.general_error, R.string.no_available_dir);\n}","preventionTips":["Call takePersistableUriPermission for the chosen SAF tree so access survives restarts.","Verify canWrite() before persisting the chosen path.","Prefer internal storage or a known-writable SD card partition.","Guide the user to pick a writable location in the picker."],"tags":["android","storage","saf","permissions","downloads","settings"],"backgroundTag":null,"analyzedSha":"9e8be091560a69f35d44bd252eb00bc7911c977b","analyzedAt":"2026-08-14T00:11:33.519Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}