beemdevelopment/Aegis · error · IOException

Unable to create directory

Error message

Unable to create directory %s

What it means

scheduleBackup stages the vault into <cacheDir>/backup before handing it to VaultBackupManager. If the directory does not exist and File.mkdir() fails, it throws an IOException('Unable to create directory %s'). mkdir() fails only when the parent is missing or a filesystem error occurs (permissions, disk full, I/O error).

Solutions

  1. Check free space and clear app cache (or Settings > Storage) so cache writes succeed, then retry the backup
  2. Use mkdirs() and tolerate 'already exists' instead of bare mkdir() so a stale file/race doesn't abort: if (!dir.exists() && !dir.isDirectory() && !dir.mkdirs()) throw ...
  3. Restart the app to reinitialize a healthy cache directory if the cache dir is in a bad state
  4. Investigate SELinux/ROM restrictions if mkdir consistently fails on this device profile

Example fix

// before
File dir = new File(_context.getCacheDir(), "backup");
if (!dir.exists() && !dir.mkdir()) {
    throw new IOException(String.format("Unable to create directory %s", dir));
}
// after
File dir = new File(_context.getCacheDir(), "backup");
if (!dir.isDirectory() && !dir.mkdirs()) {
    throw new IOException(String.format("Unable to create directory %s", dir));
}
Defensive patterns

Strategy: try-catch

Validate before calling

File dir = new File(context.getCacheDir(), "backup");
if (!dir.isDirectory() && !dir.mkdirs()) {
    Log.e(TAG, "cannot create " + dir + "; free space: " + dir.getUsableSpace());
}

Type guard

boolean canStageBackup(Context ctx) {
    File dir = new File(ctx.getCacheDir(), "backup");
    return (dir.isDirectory() || dir.mkdirs()) && dir.getUsableSpace() > MIN_BACKUP_BYTES;
}

Try / catch

try {
    vaultManager.scheduleBackup();
} catch (VaultRepositoryException e) {
    if (e.getCause() instanceof IOException && e.getMessage().contains("Unable to create directory")) {
        notifyStorageProblem();
    }
}

Prevention

When it happens

Trigger: cacheDir/backup cannot be created: app cache storage unreadable/wiped concurrently, disk full, read-only filesystem, or a non-directory file named 'backup' already occupies the path (mkdir returns false for existing non-dir).

Common situations: Device storage full; OEM cache cleaners racing the backup; broken cache state after restore; tests/emulators with restricted storage.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


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

Appendix: source

Thrown at app/src/main/java/com/beemdevelopment/aegis/vault/VaultManager.java:170

            if (_prefs.isAndroidBackupsEnabled()) {
                backedUp = true;
                scheduleAndroidBackup();
            }
        }

        if (!backedUp) {
            _prefs.setIsBackupReminderNeeded(true);
        }
    }

    public void scheduleBackup() throws VaultRepositoryException {
        _prefs.setIsBackupReminderNeeded(false);

        try {
            File dir = new File(_context.getCacheDir(), "backup");
            if (!dir.exists() && !dir.mkdir()) {
                throw new IOException(String.format("Unable to create directory %s", dir));
            }

            File tempFile = File.createTempFile(VaultBackupManager.FILENAME_PREFIX, ".json", dir);
            try (OutputStream outStream = new FileOutputStream(tempFile)) {
                _repo.export(outStream);
            }
            BackupsVersioningStrategy strategy = _prefs.getBackupVersioningStrategy();
            Uri uri = _prefs.getBackupsLocation();
            int versionsToKeep = _prefs.getBackupsVersionCount();

            _backups.scheduleBackup(tempFile, strategy, uri, versionsToKeep);
        } catch (IOException e) {
            throw new VaultRepositoryException(e);
        }
    }

    public void scheduleAndroidBackup() {
        _prefs.setIsBackupReminderNeeded(false);

View on GitHub (pinned to d6f4e5925a)