beemdevelopment/Aegis · error

Type unsupported by GoogleAuthProtos

Error message

Type unsupported by GoogleAuthProtos: %s

What it means

GoogleAuthInfo.getUri builds a Google Authenticator export (otpauth-migration://) URI and maps each entry's OTP type to a GoogleAuthProtos.MigrationPayload.OtpType enum. If an entry's type is neither HOTP nor TOTP (e.g. MOTP or Steam), the switch falls through to default and this GoogleAuthInfoException is thrown, since the protobuf schema has no representation for that type.

Solutions

  1. Exclude entries whose OTP type is not HOTP/TOTP from the Google Authenticator export selection before calling export().
  2. Check info.getOtpInfo().getType() against supported types and filter: only pass entries where type is 'TOTP' or 'HOTP'.
  3. If support is required, add a case to the switch mapping the new type to an OtpType (or extend the proto) in GoogleAuthInfo.

Example fix

// before
List<VaultEntry> selected = entries; // includes mOTP entries
GoogleAuthInfo.export(selected);

// after
List<VaultEntry> selected = entries.stream()
    .filter(e -> e.getOtpInfo().getType().equals(TotpInfo.ID)
              || e.getOtpInfo().getType().equals(HotpInfo.ID))
    .collect(Collectors.toList());
GoogleAuthInfo.export(selected);
Defensive patterns

Strategy: validation

Validate before calling

boolean exportable = info.getOtpInfo().getType().equals(TotpInfo.ID)
    || info.getOtpInfo().getType().equals(HotpInfo.ID);

Type guard

boolean isGoogleExportable(OtpInfo otp) {
    String t = otp.getType();
    return TotpInfo.ID.equals(t) || HotpInfo.ID.equals(t);
}

Try / catch

try {
    Uri uri = GoogleAuthInfo.export(entries);
} catch (GoogleAuthInfoException e) {
    // e.getMessage() names the unsupported type; fall back to filtering entries
    entries = entries.stream().filter(this::isGoogleExportableEntry).collect(Collectors.toList());
}

Prevention

When it happens

Trigger: Calling GoogleAuthInfo.export() / exportGoogleUris() (directly or via testDeepLinkIntent) while the selected entries include an OtpInfo whose typeId is not TotpInfo.ID or HotpInfo.ID — e.g. a MotpInfo or Steam-based entry — causing the switch's default branch at GoogleAuthInfo.java:449 to execute.

Common situations: Users add mOTP or Steam custom entries in Aegis, then attempt 'Export to Google Authenticator'; also common when new OTP types are added to the app before the migration exporter is updated.

Related errors


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

Appendix: source

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

                        parameters.setDigits(GoogleAuthProtos.MigrationPayload.DigitCount.DIGIT_COUNT_SIX);
                        break;
                    case 8:
                        parameters.setDigits(GoogleAuthProtos.MigrationPayload.DigitCount.DIGIT_COUNT_EIGHT);
                        break;
                    default:
                        throw new GoogleAuthInfoException(info.getUri(), String.format("Unsupported number of digits: %s", info.getOtpInfo().getDigits()));
                }

                switch (info.getOtpInfo().getType().toLowerCase()) {
                    case HotpInfo.ID:
                        parameters.setType(GoogleAuthProtos.MigrationPayload.OtpType.OTP_TYPE_HOTP);
                        parameters.setCounter(((HotpInfo) info.getOtpInfo()).getCounter());
                        break;
                    case TotpInfo.ID:
                        parameters.setType(GoogleAuthProtos.MigrationPayload.OtpType.OTP_TYPE_TOTP);
                        break;
                    default:
                        throw new GoogleAuthInfoException(info.getUri(), String.format("Type unsupported by GoogleAuthProtos: %s", info.getOtpInfo().getType()));
                }

                builder.addOtpParameters(parameters.build());
            }

            Uri.Builder exportUriBuilder = new Uri.Builder()
                    .scheme(SCHEME_EXPORT)
                    .authority("offline");

            String data = Base64.encode(builder.build().toByteArray());
            exportUriBuilder.appendQueryParameter("data", data);

            return exportUriBuilder.build();
        }
    }
}

View on GitHub (pinned to d6f4e5925a)