MuntashirAkon/AppManager · error · IOException
Archive is encrypted but no password given
Error message
Archive is encrypted but no password given
What it means
IOException from AndroidBackupHeader.read: the header declares an encryption algorithm, but no password (or an empty one) was supplied, so the AES-256 encrypted payload cannot be decrypted. The library refuses to continue rather than produce garbage output.
Solutions
- Supply the backup password via the password parameter (char[]) when constructing the extractor/header
- Re-ask the user for the password and pass it non-empty
- If the password is unknown, the archive cannot be restored — create a new backup
- Confirm the archive really is yours; encrypted backups without the password are unrecoverable by design
Example fix
// before AndroidBackupHeader header = new AndroidBackupHeader(backupStream, null); InputStream tar = header.toTar(); // after char[] password = promptForPassword(); // non-empty AndroidBackupHeader header = new AndroidBackupHeader(backupStream, password); InputStream tar = header.toTar();
Defensive patterns
Strategy: try-catch
Validate before calling
// Detect encryption requirement from header before parsing
String encLine = peekHeaderLine(backupFile, 3); // 0-based: magic, version, encryption
boolean encrypted = !"none".equals(encLine);
if (encrypted && (password == null || password.length == 0)) {
throw new IllegalArgumentException("Backup is encrypted; password required");
} Try / catch
try {
InputStream tar = header.toTar();
} catch (IOException e) {
if (e.getMessage().contains("no password given")) {
char[] pw = promptUserForPassword();
header = new AndroidBackupHeader(reopen(backupFile), pw);
tar = header.toTar();
} else throw e;
} Prevention
- Always prompt for a password when the header encryption line != 'none'
- Pass char[] not String for passwords, and null it after use
- Record whether backups were created encrypted
- Handle 'none' explicitly in restore scripts
When it happens
Trigger: Calling toTar()/read() on an encrypted .ab backup while the extractor/header was constructed with a null or empty char[] password.
Common situations: Restoring an adb backup created with 'adb backup -apk -nosystem ...' where a password was typed, but the restore code path wasn't given one; password lost/omitted in automated restore scripts.
Related errors
- Checksums for master key did not match.
- Couldn't delete old file
- Couldn't get misc.am.tsv for generating checksum
- Failed to decrypt
- Failed to decrypt
AI-assisted analysis of MuntashirAkon/AppManager@0152f468fc (2026-09-12).
Data as JSON: /api/errors/740a45db17d929a4.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/main/java/io/github/muntashirakon/AppManager/backup/adb/AndroidBackupHeader.java:93
byte[] magicBytes = BACKUP_FILE_HEADER_MAGIC.getBytes(StandardCharsets.UTF_8);
if (Arrays.equals(magicBytes, streamHeader)) {
// okay, header looks good. now parse out the rest of the fields.
String s = readHeaderLine(backupStream);
mBackupFileVersion = Integer.parseInt(s);
if (mBackupFileVersion <= BACKUP_FILE_VERSION) {
// okay, it's a version we recognize. if it's version 1, we may need
// to try two different PBKDF2 regimes to compare checksums.
final boolean pbkdf2Fallback = (mBackupFileVersion == 1);
s = readHeaderLine(backupStream);
mCompress = (Integer.parseInt(s) != 0);
s = readHeaderLine(backupStream);
if (s.equals("none")) {
// no more header to parse; we're good to go
} else if (mPassword != null && mPassword.length > 0) { // AES-256
preCompressStream = decodeAesHeaderAndInitialize(mPassword, s, pbkdf2Fallback, backupStream);
} else {
throw new IOException("Archive is encrypted but no password given");
}
} else {
throw new IOException("Wrong header version: " + s);
}
} else {
throw new IOException("Didn't read the right header magic");
}
// okay, use the right stream layer based on compression
return mCompress ? new InflaterInputStream(preCompressStream) : preCompressStream;
}
@NonNull
public OutputStream write(@NonNull OutputStream backupStream) throws Exception {
// Write the global file header. All strings are UTF-8 encoded; lines end
// with a '\n' byte. Actual backup data begins immediately following the
// final '\n'.
//View on GitHub (pinned to 0152f468fc)