beemdevelopment/Aegis · error · IOException

openOutputStream returned null

Error message

openOutputStream returned null

What it means

Guard in VaultBackupManager.createBackup(File, Uri): thrown as VaultRepositoryException when ContentResolver.openOutputStream(fileUri) returns null, meaning the provider accepted the URI but cannot supply a writable stream (destination removed or locked). The backup attempt fails and scheduleBackup records the error in Preferences.BackupResult for the UI.

Solutions

  1. Null-check the OutputStream returned by ContentResolver.openOutputStream(fileUri, "wt") and throw VaultRepositoryException naming the backup Uri
  2. Verify hasPermissionsAt(fileUri) passed and the Uri still resolves (query it) before opening the output stream
  3. Retry once with mode "w" if openOutputStream returns null for "wt", since some providers do not support truncation mode
  4. Catch SecurityException from openOutputStream and convert it to VaultBackupPermissionException so the user is prompted to re-grant access
Defensive patterns

Strategy: validation

When it happens

Trigger: Thrown at app/src/main/java/com/beemdevelopment/aegis/vault/VaultBackupManager.java:96 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of beemdevelopment/Aegis@d6f4e5925a (2026-09-08). Data as JSON: /api/errors/61b50831c3faf384. Report an issue: GitHub.

Appendix: source

Thrown at app/src/main/java/com/beemdevelopment/aegis/vault/VaultBackupManager.java:96

            createBackup(tempFile, uri, versionsToKeep);
        } else {
            throw new VaultRepositoryException("Invalid backups versioning strategy");
        }
    }

    private void createBackup(File tempFile, Uri fileUri)
            throws VaultRepositoryException, VaultBackupPermissionException {
        Log.i(TAG, String.format("Creating backup at %s", fileUri));
        try {
            if (!hasPermissionsAt(fileUri)) {
                throw new VaultBackupPermissionException("No persisted URI permissions");
            }
            ContentResolver resolver = _context.getContentResolver();
            try (FileInputStream inStream = new FileInputStream(tempFile);
                 OutputStream outStream = resolver.openOutputStream(fileUri, "wt")
            ) {
                if (outStream == null) {
                    throw new IOException("openOutputStream returned null");
                }
                IOUtils.copy(inStream, outStream);
            } catch (IOException exception) {
                throw new VaultRepositoryException(exception);
            }
        } catch (VaultRepositoryException | VaultBackupPermissionException exception) {
            Log.e(TAG, String.format("Unable to create backup: %s", exception));
            throw exception;
        } finally {
            tempFile.delete();
        }
    }

    private void createBackup(File tempFile, Uri dirUri, int versionsToKeep)
            throws VaultRepositoryException, VaultBackupPermissionException {
        FileInfo fileInfo = new FileInfo(FILENAME_PREFIX);
        DocumentFile dir = DocumentFile.fromTreeUri(_context, dirUri);

View on GitHub (pinned to d6f4e5925a)