beemdevelopment/Aegis · error

Secret is empty

Error message

Secret is empty

What it means

Thrown by GoogleAuthInfo.parseUri(Uri) after 'secret' decodes to a zero-length byte array. The URI passed the scheme and secret-presence checks, but the secret value itself (base32 or hex) decodes to nothing, e.g. an empty or all-whitespace secret parameter, so no valid OTP key can be constructed.

Solutions

  1. Provide the actual Base32 secret in the URI's secret parameter
  2. Check the upstream configuration/variable feeding the URI for emptiness
  3. Validate the secret is non-empty before constructing the URI

Example fix

// before
String uri = "otpauth://totp/x?secret=";
// after
if (secret == null || secret.isEmpty()) throw new IllegalArgumentException("secret required");
String uri = "otpauth://totp/x?secret=" + secret;
Defensive patterns

Strategy: validation

Validate before calling

String p = uri.getQueryParameter("secret"); if (p == null || p.replaceAll("=", "").isEmpty()) throw new IllegalArgumentException("secret empty");

Try / catch

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

Prevention

When it happens

Trigger: parseUri(Uri) with secret= (empty string) or a value consisting only of Base32 padding '=' characters.

Common situations: URI templates left un-filled (secret=), scripts building URIs from an empty secret variable, or corrupt QR payloads.

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/d5c112a2f1a21e4d. Report an issue: GitHub.

Appendix: source

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

        String scheme = uri.getScheme();
        if (scheme == null || !(scheme.equals(SCHEME) || scheme.equals(MotpInfo.SCHEME))) {
            throw new GoogleAuthInfoException(uri, String.format("Unsupported protocol: %s", scheme));
        }

        // 'secret' is a required parameter
        String encodedSecret = uri.getQueryParameter("secret");
        if (encodedSecret == null) {
            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;

View on GitHub (pinned to d6f4e5925a)