beemdevelopment/Aegis · error · ParseException

Secret cannot be empty

Error message

Secret cannot be empty

What it means

After decoding the secret (hex for MOTP, base32 via GoogleAuthInfo.parseSecret otherwise), EditEntryActivity.parseEntry() throws this ParseException when the decoded byte array has length 0. A zero-length secret cannot produce OTP codes, so Aegis rejects it at save time.

Solutions

  1. Enter the real base32 secret from your provider (for MOTP, the hex secret)
  2. Verify the pasted secret is complete and not a placeholder like 'AAAA' padding only
  3. Re-scan or re-copy the provisioning secret and save again

Example fix

// before
secretField.setText("===="); // decodes to zero bytes
// after
secretField.setText("JBSWY3DPEHPK3PXP");
Defensive patterns

Strategy: validation

Validate before calling

String secret = new String(EditTextHelper.getEditTextChars(_textSecret)).trim();
if (secret.isEmpty()) {
    _textSecretLayout.setError("Secret is required");
    return;
}

Try / catch

try {
    saveEntry();
} catch (ParseException e) {
    if ("Secret cannot be empty".equals(e.getMessage())) {
        _textSecretLayout.setError("Secret decodes to empty — re-enter it");
    }
}

Prevention

When it happens

Trigger: Saving an entry whose secret text decodes successfully but yields an empty byte array — e.g. an empty/whitespace-only base32 string or an empty hex string for MOTP.

Common situations: Pasting a placeholder or blank secret, or a secret consisting only of base32 padding characters that decode to zero bytes.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of beemdevelopment/Aegis@d6f4e5925a (2026-09-08). Data as JSON: /api/errors/812990ee7a4848fe. Report an issue: GitHub.

Appendix: source

Thrown at app/src/main/java/com/beemdevelopment/aegis/ui/EditEntryActivity.java:751

            }
        }

        int digits;
        try {
            digits = Integer.parseInt(_textDigits.getText().toString());
        } 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:

View on GitHub (pinned to d6f4e5925a)