{"record":{"id":"b08292ea95b15959","repo":"MuntashirAkon/AppManager","slug":"couldn-t-verify-metadata-file-nfile-infofile-nfound-checksum","errorCode":null,"errorMessage":"Couldn't verify metadata file.\\nFile: \" + infoFile + \"\\nFound: \" + checksum + \"\\nRequired: \" + mChecksum.get(infoFile.getName())","messagePattern":"Couldn't verify metadata file\\.\\\\nFile: \" \\+ infoFile \\+ \"\\\\nFound: \" \\+ checksum \\+ \"\\\\nRequired: \" \\+ mChecksum\\.get\\(infoFile\\.getName\\(\\)\\)","errorType":"exception","errorClass":"BackupException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/backup/VerifyOp.java","lineNumber":118,"sourceCode":"        } catch (BackupException e) {\n            throw e;\n        } catch (Throwable th) {\n            throw new BackupException(\"Unknown error occurred\", th);\n        }\n    }\n\n    private void verifyMetadata() throws BackupException {\n        boolean isV5AndUp = mBackupItem.isV5AndUp();\n        if (isV5AndUp) {\n            Path infoFile;\n            try {\n                infoFile = mBackupItem.getInfoFile();\n            } catch (IOException e) {\n                throw new BackupException(\"Could not get metadata file.\", e);\n            }\n            String checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, infoFile);\n            if (!checksum.equals(mChecksum.get(infoFile.getName()))) {\n                throw new BackupException(\"Couldn't verify metadata file.\" +\n                        \"\\nFile: \" + infoFile +\n                        \"\\nFound: \" + checksum +\n                        \"\\nRequired: \" + mChecksum.get(infoFile.getName()));\n            }\n        }\n        Path metadataFile;\n        try {\n            metadataFile = isV5AndUp ? mBackupItem.getMetadataV5File(false) : mBackupItem.getMetadataV2File();\n        } catch (IOException e) {\n            throw new BackupException(\"Could not get metadata file.\", e);\n        }\n        String checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, metadataFile);\n        if (!checksum.equals(mChecksum.get(metadataFile.getName()))) {\n            throw new BackupException(\"Couldn't verify metadata file.\" +\n                    \"\\nFile: \" + metadataFile +\n                    \"\\nFound: \" + checksum +\n                    \"\\nRequired: \" + mChecksum.get(metadataFile.getName()));\n        }","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/backup/VerifyOp.java#L100-L136","documentation":"VerifyOp.verifyMetadata() fails while checking the backup-info.json file (only for v5+ backups): the SHA digest of the info file on disk does not equal the digest recorded in the backup's checksum file. This means the info file was modified or corrupted after the backup was created, or the checksum entry is missing/stale. It is thrown as a BackupException so restore/verify aborts before trusting the backup metadata.","triggerScenarios":"DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, infoFile) != mChecksum.get(infoFile.getName()) during VerifyOp construction (verifyMetadata), for backups with format v5 and above; also thrown when the checksum file has no entry for the info file (get returns null).","commonSituations":"User edited backup-info.json by hand (e.g. to change flags or metadata) before restoring; partial/corrupted copy of the backup directory (truncated file during transfer); backup made on an older App Manager version whose info-file layout differs; files restored from cloud storage with line-ending or encoding changes.","solutions":["Recreate the backup so the info file and its recorded checksum are regenerated consistently.","Recompute the checksum of the info file with the recorded algorithm (e.g. sha256sum) and replace the corresponding entry in the backup's checksum file if the modification was intentional.","Re-transfer the backup directory from its source — the file may be corrupted in transit.","If checksum entry is simply absent, add an entry for the info file name in the checksum file using mBackupInfo.checksumAlgo."],"exampleFix":"// before (hand-edited backup-info.json, restore fails)\n// after: regenerate checksum entry for the info file\n// $ sha256sum backup-info.json  -> update entry in backup.checksums","handlingStrategy":"validation","validationCode":"// Before constructing VerifyOp: recompute and compare the info-file digest\nString algo = backupInfo.checksumAlgo;\nString found = DigestUtils.getHexDigest(algo, backupItem.getInfoFile());\nif (!found.equals(checksums.get(\"backup-info.json\"))) {\n    throw new IllegalStateException(\"backup-info.json modified; regenerate checksums\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    new VerifyOp(backupItem);\n} catch (BackupException e) {\n    if (e.getMessage().startsWith(\"Couldn't verify metadata file\")) {\n        // prompt user to re-copy or re-create the backup\n    }\n}","preventionTips":["Never hand-edit files inside a backup directory without regenerating the checksum file.","Always copy the entire backup directory (info, metadata, data, checksums) together.","Verify backups right after creating them, before deleting the source.","Use binary-safe transfer methods (adb pull, tar) rather than text-mode copies."],"tags":["backup","integrity","checksum","android"],"backgroundTag":"checksum-mismatch","analyzedSha":"0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5","analyzedAt":"2026-09-12T14:03:37.243Z","contentChangedAt":"2026-09-12T14:03:37.243Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}