{"record":{"id":"f9574b9f79d27464","repo":"MuntashirAkon/AppManager","slug":"could-not-cache-splits","errorCode":null,"errorMessage":"Could not cache splits","messagePattern":"Could not cache splits","errorType":"exception","errorClass":"BackupException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/backup/convert/SBConverter.java","lineNumber":337,"sourceCode":"        try {\n            mFilesToBeDeleted.add(getExtDataFile());\n            flags.addFlag(BackupFlags.BACKUP_EXT_DATA);\n            flags.addFlag(BackupFlags.BACKUP_CACHE);\n        } catch (FileNotFoundException ignore) {\n        }\n        metadataV2.flags = flags;\n        metadataV2.dataDirs = ConvertUtils.getDataDirs(mPackageName, mUserId, flags.backupInternalData(),\n                flags.backupExternalData(), flags.backupMediaObb());\n        try {\n            mFilesToBeDeleted.add(getSplitFile());\n            metadataV2.isSplitApk = true;\n        } catch (FileNotFoundException e) {\n            metadataV2.isSplitApk = false;\n        }\n        try {\n            metadataV2.splitConfigs = cacheAndGetSplitConfigs();\n        } catch (IOException | RemoteException e) {\n            throw new BackupException(\"Could not cache splits\", e);\n        }\n        metadataV2.userId = mUserId;\n        metadataV2.tarType = Prefs.BackupRestore.getCompressionMethod();\n        metadataV2.keyStore = false;\n        metadataV2.installer = Prefs.Installer.getInstallerPackageName();\n        return metadataV2;\n    }\n\n    @NonNull\n    private Path getApkFile() throws FileNotFoundException {\n        return mBackupLocation.findFile(mPackageName + \".app\");\n    }\n\n    @NonNull\n    private Path getSplitFile() throws FileNotFoundException {\n        return mBackupLocation.findFile(mPackageName + \".splits\");\n    }\n","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/backup/convert/SBConverter.java#L319-L355","documentation":"Thrown by SBConverter.generateMetadata when cacheAndGetSplitConfigs() fails to cache the APK split configuration files, via IOException (file I/O while copying splits into cache) or RemoteException ( PackageManager IPC failure). Splits are needed to record splitConfigs in the destination metadata for split-APK apps.","triggerScenarios":"A split-APK source backup whose split files are missing/unreadable mid-copy (IOException), or PackageManager binder calls dying during split resolution (RemoteException, e.g., system_server pressure or permission issues).","commonSituations":"Split config files truncated in the source archive; storage full during split caching; binder transaction failures on heavily loaded devices; converting split-APK backups where only base.apk was exported but metadata claims isSplitApk.","solutions":["Check the cause: IOException means verify all split files exist and are readable in the source; RemoteException means retry once the system is stable.","Ensure the source archive contains every split listed in the original backup, not just base.apk.","Free cache/storage space so split copying can complete.","If the app truly has no splits, ensure the source is exported as a non-split (single APK) backup."],"exampleFix":"// before: convert with incomplete splits\nconverter.convert();\n// after: verify splits before converting\nfor (String split : expectedSplits) {\n    if (!new File(sourceDir, split).isFile())\n        throw new IllegalStateException(\"missing split: \" + split);\n}\nconverter.convert();","handlingStrategy":"try-catch","validationCode":"if (metadata.isSplitApk) {\n    for (String split : metadata.splitConfigs) {\n        if (!new File(sourceDir, split).isFile())\n            throw new IllegalStateException(\"split missing in source: \" + split);\n    }\n}","typeGuard":null,"tryCatchPattern":"try { converter.convert(); }\ncatch (BackupException e) {\n    if (e.getMessage().equals(\"Could not cache splits\")\n            && e.getCause() instanceof RemoteException) {\n        // transient binder failure: wait and retry once\n    }\n}","preventionTips":["Export split-APK backups completely, including all split configs","Distinguish IOException (missing/corrupt splits) from RemoteException (binder, retryable)","Keep device storage free during split caching","Retry after system load subsides when the cause is RemoteException"],"tags":["android","backup","apk-splits","binder"],"backgroundTag":"file-read-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"}