{"record":{"id":"7e3e7745f8d5e325","repo":"MuntashirAkon/AppManager","slug":"couldn-t-verify-misc-file-nfile-miscfile-nfound-checksum","errorCode":null,"errorMessage":"Couldn't verify misc file.\\nFile: ${miscFile}\\nFound: ${checksum}\\nRequired: ${mChecksum.get(miscFile.getName())}","messagePattern":"Couldn't verify misc file\\.\\\\nFile: (.+?)\\\\nFound: (.+?)\\\\nRequired: (.+?)","errorType":"exception","errorClass":"BackupException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/backup/RestoreOp.java","lineNumber":733,"sourceCode":"                // downgrading from an Android to another. It's better to simply suppress these\n                // exceptions instead of causing a failure or worse, a crash\n                Log.e(TAG, e);\n            }\n        }\n    }\n\n    private void loadMiscRules(final PseudoRules rules) throws BackupException {\n        Path miscFile;\n        try {\n            miscFile = mBackupItem.getMiscFile();\n        } catch (IOException e) {\n            // There are no permissions, just skip\n            return;\n        }\n        if (!mRequestedFlags.skipSignatureCheck()) {\n            String checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, miscFile);\n            if (!checksum.equals(mChecksum.get(miscFile.getName()))) {\n                throw new BackupException(\"Couldn't verify misc file.\" +\n                        \"\\nFile: \" + miscFile +\n                        \"\\nFound: \" + checksum +\n                        \"\\nRequired: \" + mChecksum.get(miscFile.getName()));\n            }\n        }\n        // Decrypt permission file\n        try {\n            miscFile = mBackupItem.decrypt(new Path[]{miscFile})[0];\n        } catch (IOException | IndexOutOfBoundsException e) {\n            throw new BackupException(\"Failed to decrypt \" + miscFile.getName(), e);\n        }\n        try {\n            rules.loadExternalEntries(miscFile);\n        } catch (Throwable e) {\n            throw new BackupException(\"Failed to load rules from misc.\", e);\n        }\n    }\n","sourceCodeStart":715,"sourceCodeEnd":751,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/backup/RestoreOp.java#L715-L751","documentation":"Thrown by loadMiscRules when the misc (permissions) file fails its integrity check: the computed checksum (using the backup's checksum algorithm) does not match the checksum recorded in the backup metadata. This guard only runs when signature checking is not skipped, protecting against a corrupted or tampered misc file.","triggerScenarios":"DigestUtils.getHexDigest(checksumAlgo, miscFile) returns a value different from mChecksum.get(miscFile.getName()) — the misc file's content changed after backup creation or the checksum map lacks/corrupts the entry.","commonSituations":"Backup files edited or re-compressed after creation; partial/corrupted file transfer; restoring a hand-modified misc file; metadata checksums missing because the backup was assembled manually from partial files.","solutions":["Re-copy the original backup from its source so the misc file matches its recorded checksum","Use the restore option to skip signature/checksum verification only if you trust the backup source","Re-create the backup so checksums are regenerated for the current files","Verify disk integrity (bad sectors/SD card corruption) if checksums repeatedly fail"],"exampleFix":"// before\nnew RestoreOp(context, backupItem, new RestoreRequestFlags(/* skipSignatureCheck */ false, ...));\n// after\n// only skip verification if the backup came from a trusted, checksum-unverifiable source\nnew RestoreOp(context, backupItem, new RestoreRequestFlags(/* skipSignatureCheck */ true, ...));","handlingStrategy":"validation","validationCode":"String expected = metadata.checksums.get(miscFileName);\nString actual = DigestUtils.getHexDigest(metadata.checksumAlgo, new File(backupDir, miscFileName));\nif (!actual.equals(expected)) throw new IllegalStateException(\"Backup misc file is corrupt; refusing restore\");","typeGuard":null,"tryCatchPattern":"try {\n    restoreOp.runRestore();\n} catch (BackupException e) {\n    if (e.getMessage().startsWith(\"Couldn't verify misc file\")) {\n        showIntegrityWarningAndOfferSkipSignatureCheck();\n    } else throw e;\n}","preventionTips":["Never edit files inside an existing backup folder","Transfer backups with integrity-checked methods","Compare found vs required checksums to identify the divergent file","Keep backups on reliable storage"],"tags":["android","backup","checksum","integrity","misc"],"backgroundTag":"checksum-mismatch","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"}