{"record":{"id":"ad7cf1c33f1c8a16","repo":"MuntashirAkon/AppManager","slug":"failed-to-restore-data-files-for-index-index","errorCode":null,"errorMessage":"Failed to restore data files for index ${index}.","messagePattern":"Failed to restore data files for index (.+?)\\.","errorType":"exception","errorClass":"BackupException","httpStatus":null,"severity":"error","filePath":"app/src/main/java/io/github/muntashirakon/AppManager/backup/RestoreOp.java","lineNumber":589,"sourceCode":"            }\n            if (!dataDirectoryInfo.isExternal()) {\n                // Restore UID, GID\n                dataSourceFile.setUidGid(uidGidPair);\n            }\n        }\n        // Decrypt data\n        try {\n            dataFiles = mBackupItem.decrypt(dataFiles);\n        } catch (IOException e) {\n            throw new BackupException(\"Failed to decrypt \" + Arrays.toString(dataFiles), e);\n        }\n        // Extract data to the data directory\n        try {\n            String publicSourceDir = new File(Objects.requireNonNull(mPackageInfo.applicationInfo).publicSourceDir).getParent();\n            TarUtils.extract(mBackupInfo.tarType, dataFiles, dataSourceFile, null, BackupUtils\n                    .getExcludeDirs(!mRequestedFlags.backupCache(), null), publicSourceDir);\n        } catch (Throwable th) {\n            throw new BackupException(\"Failed to restore data files for index \" + index + \".\", th);\n        }\n        // Restore UID and GID\n        if (!Runner.runCommand(String.format(Locale.ROOT, \"chown -R %d:%d \\\"%s\\\"\", uidGidPair.uid, uidGidPair.gid, dataSourceFile.getFilePath())).isSuccessful()) {\n            if (!Utils.isRoboUnitTest()) {\n                throw new BackupException(\"Failed to restore ownership info for index \" + index + \".\");\n            } // else Don't care about permissions\n        }\n        // Restore context\n        if (!dataDirectoryInfo.isExternal()) {\n            Runner.runCommand(new String[]{\"restorecon\", \"-R\", dataSourceFile.getFilePath()});\n        }\n    }\n\n    private void restoreAdb(int index) throws BackupException {\n        Path[] dataFiles = mBackupItem.getDataFiles(index);\n        if (dataFiles.length != 1) {\n            throw new BackupException(\"ADB restore is requested but there are no .ab files.\");\n        }","sourceCodeStart":571,"sourceCodeEnd":607,"githubUrl":"https://github.com/MuntashirAkon/AppManager/blob/0152f468fc9463ee02dc2ca83f6fe4989a2c4ca5/app/src/main/java/io/github/muntashirakon/AppManager/backup/RestoreOp.java#L571-L607","documentation":"restoreDirectory extracts the decrypted data archives into the target directory via TarUtils.extract, wrapping any Throwable in this BackupException tagged with the data directory index. It means the tar (gzip/zstd etc.) archives could not be unpacked — corrupt archive, unsupported compression, or extraction I/O failure.","triggerScenarios":"TarUtils.extract throws: corrupt/truncated .tar or .tar.gz; archive compressed with a format the device's tar doesn't support (e.g. zstd binaries missing); target filesystem full or read-only mid-extract; exclusion/SELinux path issues passing an invalid publicSourceDir.","commonSituations":"Backups compressed with a newer tool than the restore environment supports; partial downloads/syncs producing truncated archives; restoring onto full internal storage; App Manager version mismatch changing tarType handling.","solutions":["Free up storage space on the target partition and retry the restore.","Verify the data archives are complete (sizes/checksums) and re-copy from the original source if truncated.","Confirm the compression format is supported on the device (install/enable the matching busybox/toybox tooling) or re-create the backup with gzip.","Check the wrapped cause for the exact tar error (bad header vs. write failure).","Update App Manager on both ends so backup (tarType) and restore versions match."],"exampleFix":"// before: restoring truncated archive\nnew RestoreOp(...).runRestore(); // BackupException: failed to restore data files for index 0\n// after: validate archive before restore\nif (!isCompleteTarArchive(dataFile)) { // e.g. test via tar -tf\n    reCopyFromOriginalBackup();\n}\nrunRestore();","handlingStrategy":"retry","validationCode":"// Sanity-check archives are non-empty before extraction\nfor (Path f : dataFiles) {\n    if (Files.size(f) == 0) throw new IllegalStateException(\"Empty archive: \" + f);\n}\n","typeGuard":"boolean extractable(Path[] files) { return files.length > 0 && Files.exists(files[0]) && files[0].size() > 0; }","tryCatchPattern":"try { runRestore(); } catch (BackupException e) {\n    if (e.getMessage().contains(\"Failed to restore data files\")) {\n        Log.e(TAG, \"tar extract failed\", e.getCause()); // inspect tar error\n        freeSpaceThenRetry();\n    } else throw e;\n}","preventionTips":["Keep enough free space on the target partition (archive size + headroom).","Verify archive completeness (checksum/size) after any transfer.","Use compression formats supported on the restore device; prefer gzip for compatibility.","Match App Manager versions across backup and restore devices."],"tags":["android","backup","tar","extraction","corruption"],"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"}