{"record":{"id":"06e07b8f4037efef","repo":"yuliskov/SmartTube","slug":"failed-to-copyuritofile","errorCode":null,"errorMessage":"Failed to copyUriToFile","messagePattern":"Failed to copyUriToFile","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupAndRestoreHelper.java","lineNumber":271,"sourceCode":"    }\r\n\r\n    private void copyUriToFile(Uri uri, File outFile) {\r\n        try {\r\n            InputStream in = mContext.getContentResolver().openInputStream(uri);\r\n            OutputStream out = new FileOutputStream(outFile);\r\n\r\n            byte[] buffer = new byte[8192];\r\n            int len;\r\n            while ((len = in.read(buffer)) != -1) {\r\n                out.write(buffer, 0, len);\r\n            }\r\n\r\n            in.close();\r\n            out.close();\r\n\r\n        } catch (Exception e) {\r\n            e.printStackTrace();\r\n            throw new IllegalStateException(\"Failed to copyUriToFile\", e);\r\n        }\r\n    }\r\n\r\n    private String getFileName(Uri uri) {\r\n        Cursor cursor = mContext.getContentResolver().query(uri, null, null, null, null);\r\n        if (cursor != null) {\r\n            int nameIndex = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);\r\n            cursor.moveToFirst();\r\n            String name = cursor.getString(nameIndex);\r\n            cursor.close();\r\n            return name;\r\n        }\r\n        return null;\r\n    }\r\n\r\n    private GeneralData getGeneralData() {\r\n        return GeneralData.instance(mContext);\r\n    }\r","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/yuliskov/SmartTube/blob/3de8d90593e0166f012ca18cc3c7ba45bfd68ac4/common/src/main/java/com/liskovsoft/smartyoutubetv2/common/misc/BackupAndRestoreHelper.java#L253-L289","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Unwrap the cause: SecurityException means permission, FileNotFoundException means a stale Uri, IOException with ENOSPC means space","Re-pick the file with ACTION_OPEN_DOCUMENT and call takePersistableUriPermission where the flow allows","Check the source document exists and free space is sufficient before copying","Isolate per-item failures in the backup loop so one bad file does not abort the whole run"],"exampleFix":"// before\n// restore path uses an old persisted Uri whose grant was lost on reinstall\ncopyUriToFile(context, oldUri, targetFile); // throws\n\n// after\nIntent i = new Intent(Intent.ACTION_OPEN_DOCUMENT);\n// ... in onActivityResult:\ncontext.getContentResolver().takePersistableUriPermission(uri,\n        Intent.FLAG_GRANT_READ_URI_PERMISSION);","handlingStrategy":"try-catch","validationCode":"DocumentFile doc = DocumentFile.fromSingleUri(context, uri);\nif (doc == null || !doc.exists() || !doc.canRead()) {\n    // ask the user to re-pick the file instead of copying\n}\n// also check free space on the target directory before copying","typeGuard":null,"tryCatchPattern":"try {\n    copyUriToFile(context, uri, target);\n} catch (IllegalStateException e) {\n    Throwable cause = e.getCause() != null ? e.getCause() : e;\n    if (cause instanceof SecurityException || cause instanceof FileNotFoundException) {\n        // stale grant: prompt re-pick, continue with remaining backup items\n    } else {\n        // log cause and abort this item\n    }\n}","preventionTips":["Call takePersistableUriPermission immediately after ACTION_OPEN_DOCUMENT results","Verify exists()/canRead() and free space before copying","Structure backup loops so one failed item skips rather than aborts the run"],"tags":["android","saf","backup","content-uri","io"],"backgroundTag":"file-copy-failed","analyzedSha":"3de8d90593e0166f012ca18cc3c7ba45bfd68ac4","analyzedAt":"2026-08-22T09:19:26.383Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}