beemdevelopment/Aegis · error

Unsupported OtpInfo type

Error message

Unsupported OtpInfo type: %s

What it means

getUri builds an otpauth:// URI from an OtpInfo; it only knows TotpInfo and HotpInfo subclasses. If _info is neither (a custom or future OtpInfo subclass), a RuntimeException is thrown because there is no standard URI encoding for it. This is an internal invariant rather than bad user input.

Solutions

  1. Only pass TotpInfo/HotpInfo entries to getUri; filter or convert other types first
  2. Skip unsupported entry types during export instead of failing the whole batch
  3. Extend the if/else chain to handle the custom OtpInfo type or subclass TotpInfo/HotpInfo

Example fix

// before
GoogleAuthInfo.getUri(entry); // entry.getInfo() is a custom MotpInfo
// after
if (entry.getInfo() instanceof TotpInfo || entry.getInfo() instanceof HotpInfo) {
    GoogleAuthInfo.getUri(entry);
} else {
    continue; // skip unsupported type
}
Defensive patterns

Strategy: type-guard

Validate before calling

if (!(info instanceof TotpInfo) && !(info instanceof HotpInfo)) {
    throw new IllegalArgumentException("Only TOTP/HOTP entries can be exported");
}

Type guard

boolean exportable(VaultEntry e) {
    return e.getInfo() instanceof TotpInfo || e.getInfo() instanceof HotpInfo;
}

Try / catch

try {
    uri = GoogleAuthInfo.getUri(entry);
} catch (RuntimeException e) {
    Log.w(TAG, "Skipping non-exportable entry: " + e.getMessage());
}

Prevention

When it happens

Trigger: Calling GoogleAuthInfo.getUri (directly or via export/exportGoogleUris) on an entry whose OtpInfo is neither TotpInfo nor HotpInfo.

Common situations: Custom OtpInfo subclasses added by forks (e.g. Steam or Yandex types) passed into the Google export path, or future info types from library updates not yet handled here.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at app/src/main/java/com/beemdevelopment/aegis/otp/GoogleAuthInfo.java:301

            builder.scheme(MotpInfo.SCHEME);
            builder.appendQueryParameter("secret", Hex.encode(_info.getSecret()));
        } else {
            builder.scheme(SCHEME);

            if (_info instanceof TotpInfo) {
                if (_info instanceof SteamInfo) {
                    builder.authority("steam");
                } else if (_info instanceof YandexInfo) {
                    builder.authority(YandexInfo.HOST_ID);
                } else {
                    builder.authority("totp");
                }
                builder.appendQueryParameter("period", Integer.toString(((TotpInfo) _info).getPeriod()));
            } else if (_info instanceof HotpInfo) {
                builder.authority("hotp");
                builder.appendQueryParameter("counter", Long.toString(((HotpInfo) _info).getCounter()));
            } else {
                throw new RuntimeException(String.format("Unsupported OtpInfo type: %s", _info.getClass()));
            }

            builder.appendQueryParameter("digits", Integer.toString(_info.getDigits()));
            builder.appendQueryParameter("algorithm", _info.getAlgorithm(false));
            builder.appendQueryParameter("secret", Base32.encode(_info.getSecret()));

            if (_info instanceof YandexInfo) {
                builder.appendQueryParameter("pin", Base32.encode(((YandexInfo) _info).getPin()));
            }
        }

        if (_issuer != null && !_issuer.equals("")) {
            builder.path(String.format("%s:%s", _issuer, _accountName));
            builder.appendQueryParameter("issuer", _issuer);
        } else {
            builder.path(_accountName);
        }

View on GitHub (pinned to d6f4e5925a)