{"record":{"id":"8936df91aa9fb453","repo":"beemdevelopment/Aegis","slug":"createfile-returned-null","errorCode":null,"errorMessage":"createFile returned null","messagePattern":"createFile returned null","errorType":"exception","errorClass":"VaultRepositoryException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/com/beemdevelopment/aegis/vault/VaultBackupManager.java","lineNumber":131,"sourceCode":"        DocumentFile dir = DocumentFile.fromTreeUri(_context, dirUri);\n\n        try {\n            Log.i(TAG, String.format(\"Creating backup at %s: %s\", Uri.decode(dir.getUri().toString()), fileInfo.toString()));\n\n            if (!hasPermissionsAt(dirUri)) {\n                throw new VaultBackupPermissionException(\"No persisted URI permissions\");\n            }\n\n            // If we create a file with a name that already exists, SAF will append a number\n            // to the filename and write to that instead. We can't overwrite existing files, so\n            // just avoid that altogether by checking beforehand.\n            if (dir.findFile(fileInfo.toString()) != null) {\n                throw new VaultRepositoryException(\"Backup file already exists\");\n            }\n\n            DocumentFile file = dir.createFile(\"application/json\", fileInfo.toString());\n            if (file == null) {\n                throw new VaultRepositoryException(\"createFile returned null\");\n            }\n\n            try (FileInputStream inStream = new FileInputStream(tempFile);\n                 OutputStream outStream = _context.getContentResolver().openOutputStream(file.getUri())) {\n                if (outStream == null) {\n                    throw new IOException(\"openOutputStream returned null\");\n                }\n                IOUtils.copy(inStream, outStream);\n            } catch (IOException e) {\n                throw new VaultRepositoryException(e);\n            }\n        } catch (VaultRepositoryException | VaultBackupPermissionException e) {\n            Log.e(TAG, String.format(\"Unable to create backup: %s\", e.toString()));\n            throw e;\n        } finally {\n            tempFile.delete();\n        }\n","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/vault/VaultBackupManager.java#L113-L149","documentation":"After the existence check, createBackup calls DocumentFile.createFile('application/json', name); SAF providers can fail (unsupported MIME type, provider crash, storage full) and return null rather than throwing. The library converts that null into VaultRepositoryException('createFile returned null') so the failure is explicit.","triggerScenarios":"The DocumentsProvider backing the tree URI fails to create the file and returns null: unsupported MIME type by the provider, invalid display name characters for the provider, storage volume unavailable/full, or remote provider error.","commonSituations":"Backing up to a cloud/external provider (e.g. SD card, NAS, third-party documents provider) that doesn't accept 'application/json'; provider bug on specific OEM ROMs; SD card ejected or read-only.","solutions":["Log the provider and URI, then retry the backup to a different location (e.g. local Downloads tree) to isolate the failing provider","Try a MIME type the provider supports (e.g. 'application/octet-stream') or a simpler filename without provider-rejected characters","Verify the target storage is writable (mount state, free space) before scheduling","Catch this VaultRepositoryException in the caller and surface a backup-failed notification with actionable guidance"],"exampleFix":"// before\nDocumentFile file = dir.createFile(\"application/json\", fileInfo.toString());\n// after\nDocumentFile file = dir.createFile(\"application/json\", fileInfo.toString());\nif (file == null) {\n    Log.e(TAG, \"createFile failed for provider \" + dirUri + \"; falling back\");\n    dir = DocumentFile.fromTreeUri(context, fallbackTreeUri);\n    file = dir.createFile(\"application/octet-stream\", fileInfo.toString());\n}","handlingStrategy":"try-catch","validationCode":"if (dir == null || !dir.canWrite()) {\n    Log.e(TAG, \"destination tree not writable: \" + dirUri);\n    return;\n}","typeGuard":"boolean isUsableDestination(DocumentFile dir) {\n    return dir != null && dir.exists() && dir.canWrite();\n}","tryCatchPattern":"try {\n    backupManager.scheduleBackup(dirUri, fileInfo);\n} catch (VaultRepositoryException e) {\n    if (\"createFile returned null\".equals(e.getMessage())) {\n        showBackupDestinationProblemNotification();\n    }\n}","preventionTips":["Prefer primary-storage SAF trees over exotic third-party providers","Check free space and mount state before scheduling","Test backups against the actual provider (SD card/cloud) users will choose"],"tags":["android","saf","backup","file-create"],"backgroundTag":"file-write-failed","analyzedSha":"d6f4e5925a97e4e91593f1542085eae03432a759","analyzedAt":"2026-09-08T00:46:31.111Z","contentChangedAt":"2026-09-08T00:46:31.111Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}