beemdevelopment/Aegis · error · ParseException
Secret is not valid hexadecimal
Error message
Secret is not valid hexadecimal
What it means
EditEntryActivity.parseEntry() decodes the secret inside a try block catching EncodingException; on failure it builds the message 'Secret is not valid hexadecimal' for MOTP entries (or 'not valid base32' otherwise). This variant fires when a MOTP entry's secret is not a valid hex string, since Hex.decode rejects invalid characters or odd length.
Solutions
- Enter a valid hexadecimal string (0-9, A-F, even length) as the MOTP secret
- Check for lookalike characters (O vs 0, I vs 1) and correct them
- Confirm the entry type: if your secret is base32, switch the type to TOTP/HOTP instead of MOTP
Example fix
// before
secretField.setText("GXYZ"); // G, Y, Z not hex; odd-ish
// after
secretField.setText("0ABC"); Defensive patterns
Strategy: validation
Validate before calling
if (type.equals("motp") && !secret.matches("([0-9A-Fa-f]{2})+")) {
_textSecretLayout.setError("MOTP secret must be valid hex (even length)");
return;
} Try / catch
try {
saveEntry();
} catch (ParseException e) {
if ("Secret is not valid hexadecimal".equals(e.getMessage())) {
_textSecretLayout.setError("Enter a valid hex string");
}
} Prevention
- Validate hex format with a regex before saving MOTP entries
- Ensure even-length hex strings
- Confirm the entry type matches the secret encoding (hex=motp, base32=totp/hotp)
When it happens
Trigger: Saving an entry with type MotpInfo.ID whose secret contains non-hex characters (G-Z) or has an odd number of characters, causing Hex.decode to throw EncodingException.
Common situations: Pasting a base32 secret into a MOTP entry, typos like 'O' vs '0', or copying a truncated/odd-length hex string from the provider.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
AI-assisted analysis of beemdevelopment/Aegis@d6f4e5925a (2026-09-08).
Data as JSON: /api/errors/2bade744ecbd5a85.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java:757
} catch (NumberFormatException e) {
throw new ParseException("Digits is not an integer.");
}
byte[] secret;
try {
String secretString = new String(EditTextHelper.getEditTextChars(_textSecret));
secret = (lowerCasedType.equals(MotpInfo.ID)) ?
Hex.decode(secretString) : GoogleAuthInfo.parseSecret(secretString);
if (secret.length == 0) {
throw new ParseException("Secret cannot be empty");
}
} catch (EncodingException e) {
String exceptionMessage = (lowerCasedType.equals(MotpInfo.ID)) ?
"Secret is not valid hexadecimal" : "Secret is not valid base32.";
throw new ParseException(exceptionMessage);
}
OtpInfo info;
try {
switch (type.toLowerCase(Locale.ROOT)) {
case TotpInfo.ID:
info = new TotpInfo(secret, algo, digits, parsePeriod());
break;
case SteamInfo.ID:
info = new SteamInfo(secret, algo, digits, parsePeriod());
break;
case HotpInfo.ID:
long counter;
try {
counter = Long.parseLong(_textPeriodCounter.getText().toString());
} catch (NumberFormatException e) {
throw new ParseException("Counter is not an integer.");
}View on GitHub (pinned to d6f4e5925a)