beemdevelopment/Aegis · error · ParseException

Secret is a required field.

Error message

Secret is a required field.

What it means

EditEntryActivity.parseEntry() checks that the secret text field is non-empty before building the VaultEntry. Aegis throws this ParseException when the user attempts to save an OTP entry without entering any secret, because an OTP entry without a secret cannot generate codes.

Solutions

  1. Paste the OTP secret (base32 for TOTP/HOTP/Yandex, hexadecimal for MOTP) into the Secret field before saving
  2. Re-copy the secret from the provider's setup key or QR provisioning URI
  3. Cancel the edit if you did not intend to modify the secret

Example fix

// before
secretField.setText("");
saveEntry();
// after
secretField.setText("JBSWY3DPEHPK3PXP");
saveEntry();
Defensive patterns

Strategy: validation

Validate before calling

if (_textSecret.length() == 0) {
    _textSecretLayout.setError("Secret is required");
    return;
}

Try / catch

try {
    saveEntry();
} catch (ParseException e) {
    if ("Secret is a required field.".equals(e.getMessage())) {
        _textSecretLayout.setError("Secret is required");
    }
}

Prevention

When it happens

Trigger: Pressing save on the edit-entry screen while the Secret field has zero length (_textSecret.length() == 0); also occurs when pasting fails or the field is cleared after importing an entry with no secret.

Common situations: Manually adding a new 2FA account and forgetting to paste the base32 secret from the provider, or accidentally deleting the secret while editing an existing entry.

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/649a808ca6e0822c. Report an issue: GitHub.

Appendix: source

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

        intent.putExtra("delete", delete);

        if (saveAndBackupVault()) {
            setResult(RESULT_OK, intent);
            finish();
        }
    }

    private int parsePeriod() throws ParseException {
        try {
            return Integer.parseInt(_textPeriodCounter.getText().toString());
        } catch (NumberFormatException e) {
            throw new ParseException("Period is not an integer.");
        }
    }

    private VaultEntry parseEntry() throws ParseException {
        if (_textSecret.length() == 0) {
            throw new ParseException("Secret is a required field.");
        }

        String type = _dropdownType.getText().toString();
        String algo = _dropdownAlgo.getText().toString();
        String lowerCasedType = type.toLowerCase(Locale.ROOT);

        if (lowerCasedType.equals(YandexInfo.ID) || lowerCasedType.equals(MotpInfo.ID)) {
            int pinLength = _textPin.length();
            if (pinLength < 4) {
                throw new ParseException("PIN is a required field. Must have a minimum length of 4 digits.");
            }
            if (pinLength != 4 && lowerCasedType.equals(MotpInfo.ID)) {
                throw new ParseException("PIN must have a length of 4 digits.");
            }
        }

        int digits;
        try {

View on GitHub (pinned to d6f4e5925a)