TeamNewPipe/NewPipe · warning · IOException

No write permissions on {}

Error message

No write permissions on {}

What it means

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.

Source

Thrown at app/src/main/java/org/schabi/newpipe/settings/DownloadSettingsFragment.java:242

        // revoke permissions on the old save path (required for SAF only)
        final Context context = requireContext();

        forgetSAFTree(context, defaultPreferences.getString(key, ""));

        if (!FilePickerActivityHelper.isOwnFileUri(context, uri)) {
            // steps to acquire the selected path:
            //     1. acquire permissions on the new save path
            //     2. save the new path, if step(2) was successful
            try {
                context.grantUriPermission(context.getPackageName(), uri,
                        StoredDirectoryHelper.PERMISSION_FLAGS);

                final StoredDirectoryHelper mainStorage =
                        new StoredDirectoryHelper(context, uri, null);
                Log.i(TAG, "Acquiring tree success from " + uri.toString());

                if (!mainStorage.canWrite()) {
                    throw new IOException("No write permissions on " + uri.toString());
                }
            } catch (final IOException err) {
                Log.e(TAG, "Error acquiring tree from " + uri.toString(), err);
                showMessageDialog(R.string.general_error, R.string.no_available_dir);
                return;
            }
        } else {
            final File target = Utils.getFileForUri(uri);
            if (!target.canWrite()) {
                showMessageDialog(R.string.download_to_sdcard_error_title,
                        R.string.download_to_sdcard_error_message);
                return;
            }
            uri = Uri.fromFile(target);
        }

        defaultPreferences.edit().putString(key, uri.toString()).apply();
        updatePreferencesSummary();

View on GitHub (pinned to 9e8be09156)

Solutions

  1. Pick a different directory the app can actually write to (e.g. internal storage or a writable SD card partition).
  2. Ensure takePersistableUriPermission is called for the granted URI so permission survives restarts.
  3. Verify the storage volume is mounted and writable before selecting it.
  4. If using an SD card, confirm the card is not read-only or corrupted.
  5. On older Android versions targeting SD card writing, use the legacy file-based path instead of SAF where applicable.
Defensive patterns

Strategy: validation

Validate before calling

context.grantUriPermission(context.getPackageName(), uri, StoredDirectoryHelper.PERMISSION_FLAGS);
final StoredDirectoryHelper mainStorage = new StoredDirectoryHelper(context, uri, null);
if (!mainStorage.canWrite()) {
    // show error dialog; do not persist this path
}

Try / catch

try {
    final StoredDirectoryHelper mainStorage = new StoredDirectoryHelper(context, uri, null);
    if (!mainStorage.canWrite()) {
        throw new IOException("No write permissions on " + uri.toString());
    }
} catch (final IOException err) {
    showMessageDialog(R.string.general_error, R.string.no_available_dir);
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of TeamNewPipe/NewPipe@9e8be09156 (2026-08-14). Data as JSON: /api/errors/0ca1e439b859c6f0. Report an issue: GitHub.