{"record":{"id":"116fd4e39195bf98","repo":"MuntashirAkon/AppManager","slug":"apk-files-backup-is-requested-but-no-apk-files-have-been-116fd4","errorCode":null,"errorMessage":"APK files backup is requested but no APK files have been backed up.","messagePattern":"APK files backup is requested but no APK files have been backed up\\.","errorType":"exception","errorClass":"BackupException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/backup/convert/SBConverter.java","lineNumber":189,"sourceCode":"        Path sourceDir = mCachedApk.requireParent();\n        // Get certificate checksums\n        try {\n            String[] checksums = ConvertUtils.getChecksumsFromApk(mCachedApk, mDestMetadata.info.checksumAlgo);\n            for (int i = 0; i < checksums.length; ++i) {\n                mChecksum.add(CERT_PREFIX + i, checksums[i]);\n            }\n        } catch (Exception ignore) {\n        }\n        // Backup APK files\n        String[] apkFiles = ArrayUtils.appendElement(String.class, mDestMetadata.metadata.splitConfigs, mDestMetadata.metadata.apkName);\n        String sourceBackupFilePrefix = BackupUtils.getSourceFilePrefix(getExt(mDestMetadata.info.tarType));\n        Path[] sourceFiles;\n        try {\n            // We have to specify APK files because the folder may contain many\n            sourceFiles = TarUtils.create(mDestMetadata.info.tarType, sourceDir, mBackupItem.getUnencryptedBackupPath(), sourceBackupFilePrefix,\n                    apkFiles, null, null, false).toArray(new Path[0]);\n        } catch (Throwable th) {\n            throw new BackupException(\"APK files backup is requested but no APK files have been backed up.\", th);\n        }\n        try {\n            sourceFiles = mBackupItem.encrypt(sourceFiles);\n        } catch (IOException e) {\n            throw new BackupException(\"Failed to encrypt \" + Arrays.toString(sourceFiles));\n        }\n        for (Path file : sourceFiles) {\n            mChecksum.add(file.getName(), DigestUtils.getHexDigest(mDestMetadata.info.checksumAlgo, file));\n        }\n    }\n\n    private void backupData() throws BackupException {\n        List<Path> dataFiles = new ArrayList<>(3);\n        try {\n            if (mDestMetadata.info.flags.backupInternalData()) {\n                dataFiles.add(getIntDataFile());\n            }\n            if (mDestMetadata.info.flags.backupExternalData()) {","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/backup/convert/SBConverter.java#L171-L207","documentation":"Thrown by SBConverter.backupApkFile when TarUtils.create fails to package the requested APK (and split config) files into the destination backup archive. The converter requested an APK backup but the tar creation step failed (any Throwable), so the archive could not be produced. It wraps the underlying cause, so inspect getCause() for the real I/O or crypto error.","triggerScenarios":"Calling convert() on a Swift Backup source with APK backup flag enabled when: the cached base.apk is missing or unreadable, splitConfigs in destination metadata reference files not present in sourceDir, TarUtils hits an I/O error writing the tar, or apkName/splitConfigs are null/empty so the filter matches nothing.","commonSituations":"Corrupted or partially-extracted source backup folder; converting a split-APK backup where split config names don't match the files on disk; read-only storage; mismatch between metadata apkName and actual cached file name after an AppManager version change.","solutions":["Check the wrapped cause (BackupException.getCause()) to find the real TarUtils/I/O failure.","Verify the cached APK and all split config files named in metadata.splitConfigs exist under the cache directory (mCachedApk.requireParent()).","Confirm metadata.apkName matches the actual base APK file name; fix stale metadata if it was hand-edited.","Re-extract the source backup archive to rule out corruption, then retry the conversion.","If APK backup is not required, disable the APK flag so this step is skipped."],"exampleFix":"// before: blindly convert with stale metadata\nconverter.convert();\n// after: pre-check APK presence before converting\nFile base = new File(cacheDir, metadata.apkName);\nif (!base.isFile()) {\n    throw new IllegalStateException(\"base.apk missing: \" + base);\n}\nfor (String split : metadata.splitConfigs) {\n    if (!new File(cacheDir, split).isFile()) {\n        throw new IllegalStateException(\"missing split: \" + split);\n    }\n}\nconverter.convert();","handlingStrategy":"validation","validationCode":"String[] apkFiles = ArrayUtils.appendElement(String.class, metadata.splitConfigs, metadata.apkName);\nfor (String f : apkFiles) {\n    if (f == null || !new File(cacheDir, f).isFile())\n        throw new IllegalStateException(\"APK part missing from cache: \" + f);\n}","typeGuard":null,"tryCatchPattern":"try { converter.convert(); }\ncatch (BackupException e) {\n    if (e.getCause() != null) Log.e(TAG, \"tar creation failed\", e.getCause());\n    // abort conversion, inform user which APK part is missing\n}","preventionTips":["Always keep metadata.apkName and splitConfigs in sync with files actually present in the cache/source dir","Never hand-edit backup metadata","Re-extract source archives instead of partially copying them","Check the wrapped cause before retrying"],"tags":["android","backup","tar","io"],"backgroundTag":"file-not-found","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"}