beemdevelopment/Aegis · error
PIN must be set before generating an OTP
Error message
PIN must be set before generating an OTP
What it means
MotpInfo.getOtp requires a PIN to have been set (via a MotpInfo constructor or setPin) before it can generate an mOTP code. If _pin is still null it throws IllegalStateException, because the mOTP algorithm cannot produce a code without the PIN component.
Solutions
- Call setPin(...) (or use the constructor that takes a pin) before invoking getOtp.
- Guard with a null check: only call getOtp when the entry's PIN is configured.
- If the entry legitimately has no PIN, it is not a valid mOTP credential — fix the source data/import.
Example fix
// before
MotpInfo motp = new MotpInfo(secret, algorithm, digits, period);
String code = motp.getOtp(time); // throws
// after
MotpInfo motp = new MotpInfo(secret, algorithm, digits, period);
motp.setPin("1234");
String code = motp.getOtp(time); Defensive patterns
Strategy: validation
Validate before calling
if (motpInfo.getPin() == null) {
throw new IllegalStateException("configure the mOTP PIN before generating codes");
} Try / catch
try {
String code = motpInfo.getOtp(time);
} catch (IllegalStateException e) {
// PIN never set; prompt the user to configure the PIN
promptForPin();
} Prevention
- Always use the MotpInfo constructor variant that takes the PIN.
- Check PIN presence before calling getOtp in code that builds entries incrementally.
- Ensure deserialization always restores the PIN field.
When it happens
Trigger: Calling getOtp(time) on a MotpInfo instance that was constructed without a PIN and whose setPin was never invoked — i.e. generating a code for an mOTP entry whose PIN was never initialized (only seen in tests like testMotpInfoOtp that build MotpInfo directly).
Common situations: Programmatic use of MotpInfo where the developer builds the object incrementally and calls getOtp before setPin; deserialization paths that skip PIN assignment; partially constructed entries.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- PIN must have a length of 4 digits.
- unsupported otp type:
- unsupported otp type:
- unsupported otp type:
- Unrecognized tokenType
AI-assisted analysis of beemdevelopment/Aegis@d6f4e5925a (2026-09-08).
Data as JSON: /api/errors/592031fb49b099ba.
Report an issue: GitHub.
Appendix: source
Thrown at app/src/main/java/com/beemdevelopment/aegis/otp/MotpInfo.java:36
public static final int PERIOD = 10;
public static final int DIGITS = 6;
private String _pin;
public MotpInfo(@NonNull byte[] secret) throws OtpInfoException {
this(secret, null);
}
public MotpInfo(byte[] secret, String pin) throws OtpInfoException {
super(secret, ALGORITHM, DIGITS, PERIOD);
setPin(pin);
}
@Override
public String getOtp(long time) {
if (_pin == null) {
throw new IllegalStateException("PIN must be set before generating an OTP");
}
try {
MOTP otp = MOTP.generateOTP(getSecret(), getAlgorithm(false), getDigits(), getPeriod(), getPin(), time);
return otp.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
@Override
public String getTypeId() {
return ID;
}
@Override
public JSONObject toJson() {
JSONObject result = super.toJson();View on GitHub (pinned to d6f4e5925a)