beemdevelopment/Aegis · error

Host not present in URI

Error message

Host not present in URI: %s

What it means

Generic validation guard in parseUri(Uri): when the URI's type segment (host) does not map to a known OTP type such as totp/hotp/steam/motp, the code falls through to a default branch that reports the unrecognized host value. It fires on otpauth URIs with a wrong or missing type, e.g. otpauth://foo/...

Solutions

  1. Include the OTP type as the URI host: otpauth://totp/... or otpauth://hotp/...
  2. Re-generate the QR/URI with a standard generator library
  3. Validate the URI contains a known host before importing

Example fix

// before
String uri = "otpauth://?secret=JBSWY3DPEHPK3PXP";
// after
String uri = "otpauth://totp/Example:alice?secret=JBSWY3DPEHPK3PXP";
Defensive patterns

Strategy: validation

Validate before calling

if (uri.getHost() == null) throw new IllegalArgumentException("otpauth URI missing type host");

Type guard

boolean hasOtpType(Uri u) { return u.getHost() != null; }

Try / catch

try { return GoogleAuthInfo.parseUri(uri); } catch (GoogleAuthInfoException e) { showMalformedUriError(uri); return null; }

Prevention

When it happens

Trigger: parseUri(Uri) with a URI like otpauth://?secret=... (no host component), e.g. otpauth://totp written without the host or a malformed scheme-specific part.

Common situations: Hand-written otpauth URIs, QR generators emitting otpauth:///label forms, or strings where the type was stripped during transfer.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


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

Appendix: source

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

            throw new GoogleAuthInfoException(uri, "Parameter 'secret' is not present");
        }

        byte[] secret;
        try {
            secret = (scheme.equals(MotpInfo.SCHEME)) ? Hex.decode(encodedSecret) : parseSecret(encodedSecret);
        } catch (EncodingException e) {
            throw new GoogleAuthInfoException(uri, "Bad secret", e);
        }
        if (secret.length == 0) {
            throw new GoogleAuthInfoException(uri, "Secret is empty");
        }

        OtpInfo info;
        String issuer = "";
        try {
            String type = (scheme.equals(MotpInfo.SCHEME)) ? MotpInfo.ID : uri.getHost();
            if (type == null) {
                throw new GoogleAuthInfoException(uri, String.format("Host not present in URI: %s", uri.toString()));
            }

            switch (type) {
                case "totp":
                    TotpInfo totpInfo = new TotpInfo(secret);
                    String period = uri.getQueryParameter("period");
                    if (period != null) {
                        totpInfo.setPeriod(Integer.parseInt(period));
                    }
                    info = totpInfo;
                    break;
                case "steam":
                    SteamInfo steamInfo = new SteamInfo(secret);
                    period = uri.getQueryParameter("period");
                    if (period != null) {
                        steamInfo.setPeriod(Integer.parseInt(period));
                    }
                    info = steamInfo;

View on GitHub (pinned to d6f4e5925a)