beemdevelopment/Aegis · error · DatabaseImporterException
Unexpectedly high number of iterations
Error message
Unexpectedly high number of iterations: %d
What it means
The andOTP importer caps the PBKDF2 iteration count at 10,000,000. A larger value almost certainly means the file is not an andOTP backup, so the importer aborts early to avoid a multi-minute key derivation that would only fail at decryption time.
Solutions
- Confirm the file is an andOTP encrypted export and re-select it
- Re-export the backup from andOTP
- Check the first 4 bytes in a hex editor for a realistic iteration count (typically 10,000–1,000,000)
- Import via the correct importer for the file's actual source app
Example fix
// before
if (iterations > 10_000_000L) {
throw new DatabaseImporterException(String.format("Unexpectedly high number of iterations: %d", iterations));
}
// after
long MAX_ITERATIONS = 10_000_000L;
if (iterations > MAX_ITERATIONS) {
throw new DatabaseImporterException(String.format(
"Not an andOTP backup (iterations=%d > %d); pick the correct file/app",
iterations, MAX_ITERATIONS));
} Defensive patterns
Strategy: validation
Validate before calling
int iterations = ByteBuffer.wrap(Arrays.copyOfRange(fileBytes, 0, 4)).getInt();
if (iterations <= 0 || iterations > 10_000_000) {
throw new IllegalArgumentException("Un plausible andOTP iteration count: " + iterations);
} Try / catch
try {
importer.read(stream, password);
} catch (DatabaseImporterException e) {
if (e.getMessage().startsWith("Unexpectedly high")) {
promptUserToPickCorrectFile();
}
} Prevention
- Verify file provenance — andOTP backups only
- Hex-inspect the leading int32 for a realistic iteration value before importing
- Use the correct importer per source app
When it happens
Trigger: Importing a file whose first 4 bytes parse to an iteration count above 10,000,000 — typically a non-andOTP file or one from a different app whose header places other data where andOTP stores iterations.
Common situations: Wrong file selected during import; andOTP backup created with an absurd iteration count via manual config edit; corrupted/truncated file where high-order bytes shift the value.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Invalid number of iterations for PBKDF
- Accounts.txt
- Key not found
- Empty secret (empty authority)
- Unexpected master key KDF
AI-assisted analysis of beemdevelopment/Aegis@d6f4e5925a (2026-09-08).
Data as JSON: /api/errors/293f96caad189b51.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/main/java/com/beemdevelopment/aegis/importers/AndOtpImporter.java:127
| InvalidAlgorithmParameterException
| InvalidKeyException
| NoSuchPaddingException
| IllegalBlockSizeException e) {
throw new RuntimeException(e);
}
}
private PBKDFTask.Params getKeyDerivationParams(char[] password) throws DatabaseImporterException {
byte[] iterBytes = Arrays.copyOfRange(_data, 0, INT_SIZE);
int iterations = ByteBuffer.wrap(iterBytes).getInt();
if (iterations < 1) {
throw new DatabaseImporterException(String.format("Invalid number of iterations for PBKDF: %d", iterations));
}
// If number of iterations is this high, it's probably not an andOTP file, so
// abort early in order to prevent having to wait for an extremely long key derivation
// process, only to find out that the user picked the wrong file
if (iterations > 10_000_000L) {
throw new DatabaseImporterException(String.format("Unexpectedly high number of iterations: %d", iterations));
}
byte[] salt = Arrays.copyOfRange(_data, INT_SIZE, INT_SIZE + SALT_SIZE);
return new PBKDFTask.Params("PBKDF2WithHmacSHA1", KEY_SIZE, password, salt, iterations);
}
protected DecryptedState decryptOldFormat(char[] password) throws DatabaseImporterException {
// WARNING: DON'T DO THIS IN YOUR OWN CODE
// this exists solely to support the old andOTP backup format
// it is not a secure way to derive a key from a password
MessageDigest hash;
try {
hash = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
byte[] keyBytes = hash.digest(CryptoUtils.toBytes(password));
SecretKey key = new SecretKeySpec(keyBytes, "AES");View on GitHub (pinned to d6f4e5925a)