beemdevelopment/Aegis · error
Secret is empty
Error message
Secret is empty
What it means
OtpInfo.checkSecret is a shared guard used by concrete OTP implementations before generating a code. It throws OtpInfoException('Secret is empty') when getSecret() returns a zero-length byte array, since an OTP cannot be derived from an empty key.
Solutions
- Ensure a non-empty secret is set before generating OTPs: check secret.getBytes().length > 0 (or decode the base32 string and verify it isn't blank).
- Reject the entry at import/parse time if its secret is empty rather than storing it.
- If the entry data is valid elsewhere, re-provision the credential to obtain a real secret.
Example fix
// before
TotpInfo info = new TotpInfo(new byte[0]);
String code = info.getOtp(); // OtpInfoException: Secret is empty
// after
byte[] secret = Base32.decode(secretString);
if (secret.length == 0) {
throw new IllegalArgumentException("secret must not be empty");
}
TotpInfo info = new TotpInfo(secret); Defensive patterns
Strategy: validation
Validate before calling
if (secret == null || secret.length == 0) {
throw new IllegalArgumentException("OTP secret must not be empty");
} Type guard
boolean hasSecret(OtpInfo info) {
return info.getSecret() != null && info.getSecret().length > 0;
} Try / catch
try {
String code = otpInfo.getOtp();
} catch (OtpInfoException e) {
if ("Secret is empty".equals(e.getMessage())) {
// mark entry as invalid and ask user to re-provision
}
} Prevention
- Validate decoded secrets at import/scan time and skip empty ones.
- Never construct OtpInfo with new byte[0]; fail early at the entry-parsing layer.
- Detect truncated QR scans by checking the secret parameter exists and decodes to > 0 bytes.
When it happens
Trigger: Generating an OTP (getOtp) for any OtpInfo subclass whose secret bytes are empty — typically after constructing an OtpInfo with a zero-length secret, or after decoding an empty/blank base32 secret from a URI, QR code, or imported vault entry.
Common situations: Importing otpauth:// URIs or backup files where the secret parameter is missing or empty; scanning a partial QR code; entries corrupted during migration; tests constructing TotpInfo/HotpInfo with empty secrets.
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/e0c46a6409377ee0.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/main/java/com/beemdevelopment/aegis/otp/OtpInfo.java:35
private byte[] _secret;
private String _algorithm;
private int _digits;
public OtpInfo(byte[] secret) throws OtpInfoException {
this(secret, DEFAULT_ALGORITHM, DEFAULT_DIGITS);
}
public OtpInfo(byte[] secret, String algorithm, int digits) throws OtpInfoException {
setSecret(secret);
setAlgorithm(algorithm);
setDigits(digits);
}
public abstract String getOtp() throws OtpInfoException;
protected void checkSecret() throws OtpInfoException {
if (getSecret().length == 0) {
throw new OtpInfoException("Secret is empty");
}
}
public abstract String getTypeId();
public String getType() {
return getTypeId().toUpperCase(Locale.ROOT);
}
public JSONObject toJson() {
JSONObject obj = new JSONObject();
try {
obj.put("secret", Base32.encode(getSecret()));
obj.put("algo", getAlgorithm(false));
obj.put("digits", getDigits());
} catch (JSONException e) {
throw new RuntimeException(e);View on GitHub (pinned to d6f4e5925a)