{"record":{"id":"87a5e8c375cbca96","repo":"MuntashirAkon/AppManager","slug":"failed-to-restore-the-keystore-files","errorCode":null,"errorMessage":"Failed to restore the KeyStore files.","messagePattern":"Failed to restore the KeyStore files\\.","errorType":"exception","errorClass":"BackupException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/backup/RestoreOp.java","lineNumber":460,"sourceCode":"        // Restore KeyStore files to the /data/misc/keystore folder\n        Path keyStorePath = KeyStoreUtils.getKeyStorePath(mUserId);\n        // Note down UID/GID\n        UidGidPair uidGidPair;\n        int mode;\n        try {\n            uidGidPair = Objects.requireNonNull(keyStorePath.getFile()).getUidGid();\n            mode = keyStorePath.getFile().getMode();\n        } catch (ErrnoException e) {\n            throw new BackupException(\"Failed to access properties of the KeyStore folder.\", e);\n        }\n        try {\n            TarUtils.extract(mBackupInfo.tarType, keyStoreFiles, keyStorePath, null, null, null);\n            // Restore folder permission\n            Paths.chown(keyStorePath, uidGidPair.uid, uidGidPair.gid);\n            //noinspection OctalInteger\n            Paths.chmod(keyStorePath, mode & 0777);\n        } catch (Throwable th) {\n            throw new BackupException(\"Failed to restore the KeyStore files.\", th);\n        }\n        // Rename files\n        List<String> keyStoreFileNames = KeyStoreUtils.getKeyStoreFiles(KEYSTORE_PLACEHOLDER, mUserId);\n        for (String keyStoreFileName : keyStoreFileNames) {\n            try {\n                String newFilename = Utils.replaceOnce(keyStoreFileName, String.valueOf(KEYSTORE_PLACEHOLDER), String.valueOf(mUid));\n                keyStorePath.findFile(keyStoreFileName).renameTo(newFilename);\n                Path targetFile = keyStorePath.findFile(newFilename);\n                // Restore file permission\n                Paths.chown(targetFile, uidGidPair.uid, uidGidPair.gid);\n                //noinspection OctalInteger\n                Paths.chmod(targetFile, 0600);\n            } catch (IOException | ErrnoException e) {\n                throw new BackupException(\"Failed to rename KeyStore files\", e);\n            }\n        }\n        Runner.runCommand(new String[]{\"restorecon\", \"-R\", keyStorePath.getFilePath()});\n    }","sourceCodeStart":442,"sourceCodeEnd":478,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/backup/RestoreOp.java#L442-L478","documentation":"RestoreOp.restoreKeyStore throws this BackupException when TarUtils.extract fails to unpack the backed-up KeyStore tar entries into the KeyStore directory, or when the subsequent chown/chmod on the KeyStore folder fails. It wraps the original Throwable as the cause. It signals the KeyStore portion of an app backup could not be laid down on disk.","triggerScenarios":"TarUtils.extract() throws (corrupt/encrypted KeyStore tar, missing backup files, wrong tarType); Paths.chown() fails because the target uid:gid pair is invalid or the caller lacks root; Paths.chmod() fails on the keyStorePath.","commonSituations":"Restoring a backup on a device without root so permission changes fail; a truncated or tampered keystore.tar in the backup directory; restoring a backup made on another Android version whose /data/keystore layout changed; checksum-passing files that were later modified.","solutions":["Verify the device is rooted and App Manager has root/su access, since chown/chmod on the KeyStore path require it.","Check the integrity of the backup: confirm the KeyStore backup files exist and the tar is not truncated; re-create the backup if corrupted.","Inspect the wrapped cause (getCause()) for the underlying exception from TarUtils.extract or Paths.chown/chmod.","Confirm the backup was made on a compatible Android version; KeyStore paths/format differ across releases.","Retry the restore after rebooting (transient mount/ownership issues on /data)."],"exampleFix":"// before: blind restore that fails on non-root\ncatch (Throwable th) { throw new BackupException(\"Failed to restore the KeyStore files.\", th); }\n// after: check root before attempting\nif (!RootUtils.isRooted()) {\n    throw new BackupException(\"KeyStore restore requires root access.\");\n}\n// then proceed with TarUtils.extract(...) inside try/catch","handlingStrategy":"try-catch","validationCode":"// Before restore: confirm root and backup presence\nif (!Shell.getRootAccess()) throw new IllegalStateException(\"Root required for KeyStore restore\");\nif (keyStoreBackupFiles.length == 0) throw new IllegalStateException(\"No KeyStore files in backup\");","typeGuard":"boolean canRestoreKeyStore(BackupOp op) { return op != null && op.hasKeyStoreFiles() && Shell.getRootAccess(); }","tryCatchPattern":"try { runRestore(); } catch (BackupException e) {\n    if (e.getMessage().contains(\"KeyStore files\")) {\n        Log.e(TAG, \"KeyStore restore failed\", e.getCause());\n        // surface root/integrity guidance to the user\n    } else throw e;\n}","preventionTips":["Always run KeyStore restores with confirmed root access.","Verify backup checksums before starting the restore.","Keep the same App Manager version for backup and restore.","Read the wrapped cause to distinguish extraction vs. permission failures."],"tags":["android","backup","keystore","file-extraction","permissions"],"backgroundTag":"file-write-failed","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}