yuliskov/SmartTube · error · IllegalStateException

Failed to copyUriToFile

Error message

Failed to copyUriToFile

What it means

copyUriToFile streams a SAF content Uri (the user-picked backup file) into a local file during backup/restore; any exception from open/read/write/close is printStackTrace'd and rethrown as IllegalStateException("Failed to copyUriToFile") with the original error as cause. The cause chain — FileNotFoundException, SecurityException, ENOSPC — is the actual diagnosis; the wrapper only says the copy step failed.

Source

Thrown at common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupAndRestoreHelper.java:271

    }

    private void copyUriToFile(Uri uri, File outFile) {
        try {
            InputStream in = mContext.getContentResolver().openInputStream(uri);
            OutputStream out = new FileOutputStream(outFile);

            byte[] buffer = new byte[8192];
            int len;
            while ((len = in.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }

            in.close();
            out.close();

        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalStateException("Failed to copyUriToFile", e);
        }
    }

    private String getFileName(Uri uri) {
        Cursor cursor = mContext.getContentResolver().query(uri, null, null, null, null);
        if (cursor != null) {
            int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
            cursor.moveToFirst();
            String name = cursor.getString(nameIndex);
            cursor.close();
            return name;
        }
        return null;
    }

    private GeneralData getGeneralData() {
        return GeneralData.instance(mContext);
    }

View on GitHub (pinned to 3de8d90593)

Solutions

  1. Unwrap the cause: SecurityException means permission, FileNotFoundException means a stale Uri, IOException with ENOSPC means space
  2. Re-pick the file with ACTION_OPEN_DOCUMENT and call takePersistableUriPermission where the flow allows
  3. Check the source document exists and free space is sufficient before copying
  4. Isolate per-item failures in the backup loop so one bad file does not abort the whole run

Example fix

// before
// restore path uses an old persisted Uri whose grant was lost on reinstall
copyUriToFile(context, oldUri, targetFile); // throws

// after
Intent i = new Intent(Intent.ACTION_OPEN_DOCUMENT);
// ... in onActivityResult:
context.getContentResolver().takePersistableUriPermission(uri,
        Intent.FLAG_GRANT_READ_URI_PERMISSION);
Defensive patterns

Strategy: try-catch

Validate before calling

DocumentFile doc = DocumentFile.fromSingleUri(context, uri);
if (doc == null || !doc.exists() || !doc.canRead()) {
    // ask the user to re-pick the file instead of copying
}
// also check free space on the target directory before copying

Try / catch

try {
    copyUriToFile(context, uri, target);
} catch (IllegalStateException e) {
    Throwable cause = e.getCause() != null ? e.getCause() : e;
    if (cause instanceof SecurityException || cause instanceof FileNotFoundException) {
        // stale grant: prompt re-pick, continue with remaining backup items
    } else {
        // log cause and abort this item
    }
}

Prevention

When it happens

Trigger: The Uri read permission is missing or expired (ACTION_OPEN_DOCUMENT result used after the grant lapsed, takePersistableUriPermission never called); the source file was deleted or renamed between selection and copy; disk full or target path unwritable mid-write; ContentResolver.openInputStream returning null for the Uri.

Common situations: Restore flows reusing a persisted Uri after app reinstall (grants reset); backup file on removable storage that unmounted during the copy; device storage exhausted mid-backup.

Related errors


AI-assisted analysis of yuliskov/SmartTube@3de8d90593 (2026-08-22). Data as JSON: /api/errors/06e07b8f4037efef. Report an issue: GitHub.