MuntashirAkon/AppManager · error · BackupException
An uninstallation was necessary but couldn't perform it.
Error message
An uninstallation was necessary but couldn't perform it.
What it means
When signature verification failed but checks were skipped, restoreApkFiles() must uninstall the currently installed (differently-signed) app before installing the backed-up APK. If PackageInstallerCompat.uninstall() returns false (the uninstall did not succeed), the restore cannot proceed safely and this BackupException is thrown.
Source
Thrown at app/src/main/java/io/github/muntashirakon/AppManager/backup/RestoreOp.java:316
if (!mRequestedFlags.skipSignatureCheck()) {
String checksum;
for (Path file : backupSourceFiles) {
checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, file);
if (!checksum.equals(mChecksum.get(file.getName()))) {
throw new BackupException("Source file verification failed." +
"\nFile: " + file +
"\nFound: " + checksum +
"\nRequired: " + mChecksum.get(file.getName()));
}
}
}
if (!isVerified) {
// Signature verification failed but still here because signature check is disabled.
// The only way to restore is to reinstall the app
synchronized (sLock) {
PackageInstallerCompat installer = PackageInstallerCompat.getNewInstance();
if (installer.uninstall(mPackageName, mUserId, false)) {
throw new BackupException("An uninstallation was necessary but couldn't perform it.");
}
}
}
// Setup package staging directory
Path packageStagingDirectory = Paths.get(PackageUtils.PACKAGE_STAGING_DIRECTORY);
try {
synchronized (sLock) {
PackageUtils.ensurePackageStagingDirectoryPrivileged();
}
} catch (Exception ignore) {
}
try {
if (!packageStagingDirectory.canWrite()) {
packageStagingDirectory = mBackupItem.getUnencryptedBackupPath();
}
} catch (IOException e) {
throw new BackupException("Could not create package staging directory", e);
}View on GitHub (pinned to 0152f468fc)
Solutions
- Grant App Manager sufficient privileges (root or grant ADB/owner permissions) so it can uninstall packages.
- Manually uninstall the app first, then run the restore so no forced uninstall is needed.
- Remove device-admin/active device policies or work-profile restrictions on the target app.
- If the app is a system app, uninstall only its updates manually or use a different restore strategy (skip APK restore).
Defensive patterns
Strategy: try-catch
Validate before calling
// Before restore, ensure the installer can uninstall the target: PackageInstallerCompat installer = PackageInstallerCompat.getNewInstance(); // confirm privileges (root/adb) and that the app is not device-admin/system-locked boolean canUninstall = hasSufficientPrivileges() && !isDeviceAdmin(packageName, userId);
Try / catch
try { restoreOp.runRestore(); } catch (BackupException e) {
if (e.getMessage().contains("An uninstallation was necessary but couldn't perform it")) {
// guide user to grant privileges or uninstall the app manually, then retry
}
} Prevention
- Set up App Manager with root or ADB grants before performing signature-mismatched restores.
- Uninstall manually any differently-signed version ahead of the restore.
- Clear device-admin/policy restrictions on apps slated for restore.
When it happens
Trigger: isVerified == false (cert mismatch, signature check skipped), then installer.uninstall(mPackageName, mUserId, false) returns false during restore.
Common situations: App Manager lacks the permission/rights to uninstall (non-root without sufficient ADB privileges, device-owner restrictions); the app is a device admin or has active device policies; the app is a system app that cannot be fully uninstalled; user or work-profile restrictions block uninstallation.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- Could not delete the selected backups
- Failed to restore the KeyStore files.
- Failed to rename KeyStore files
- Could not create directory ${dataSourceFile}
- Failed to restore ownership info for index ${index}.
AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12).
Data as JSON: /api/errors/4f8ba764b9ae23e7.
Report an issue: GitHub.