{"record":{"id":"159f4c7f07453617","repo":"beemdevelopment/Aegis","slug":"unsupported-otpinfo-type-s","errorCode":null,"errorMessage":"Unsupported OtpInfo type: %s","messagePattern":"Unsupported OtpInfo type: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/src/main/java/com/beemdevelopment/aegis/otp/GoogleAuthInfo.java","lineNumber":301,"sourceCode":"            builder.scheme(MotpInfo.SCHEME);\n            builder.appendQueryParameter(\"secret\", Hex.encode(_info.getSecret()));\n        } else {\n            builder.scheme(SCHEME);\n\n            if (_info instanceof TotpInfo) {\n                if (_info instanceof SteamInfo) {\n                    builder.authority(\"steam\");\n                } else if (_info instanceof YandexInfo) {\n                    builder.authority(YandexInfo.HOST_ID);\n                } else {\n                    builder.authority(\"totp\");\n                }\n                builder.appendQueryParameter(\"period\", Integer.toString(((TotpInfo) _info).getPeriod()));\n            } else if (_info instanceof HotpInfo) {\n                builder.authority(\"hotp\");\n                builder.appendQueryParameter(\"counter\", Long.toString(((HotpInfo) _info).getCounter()));\n            } else {\n                throw new RuntimeException(String.format(\"Unsupported OtpInfo type: %s\", _info.getClass()));\n            }\n\n            builder.appendQueryParameter(\"digits\", Integer.toString(_info.getDigits()));\n            builder.appendQueryParameter(\"algorithm\", _info.getAlgorithm(false));\n            builder.appendQueryParameter(\"secret\", Base32.encode(_info.getSecret()));\n\n            if (_info instanceof YandexInfo) {\n                builder.appendQueryParameter(\"pin\", Base32.encode(((YandexInfo) _info).getPin()));\n            }\n        }\n\n        if (_issuer != null && !_issuer.equals(\"\")) {\n            builder.path(String.format(\"%s:%s\", _issuer, _accountName));\n            builder.appendQueryParameter(\"issuer\", _issuer);\n        } else {\n            builder.path(_accountName);\n        }\n","sourceCodeStart":283,"sourceCodeEnd":319,"githubUrl":"https://github.com/beemdevelopment/Aegis/blob/d6f4e5925a97e4e91593f1542085eae03432a759/app/src/main/java/com/beemdevelopment/aegis/otp/GoogleAuthInfo.java#L283-L319","documentation":"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.","triggerScenarios":"Calling GoogleAuthInfo.getUri (directly or via export/exportGoogleUris) on an entry whose OtpInfo is neither TotpInfo nor HotpInfo.","commonSituations":"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.","solutions":["Only pass TotpInfo/HotpInfo entries to getUri; filter or convert other types first","Skip unsupported entry types during export instead of failing the whole batch","Extend the if/else chain to handle the custom OtpInfo type or subclass TotpInfo/HotpInfo"],"exampleFix":"// before\nGoogleAuthInfo.getUri(entry); // entry.getInfo() is a custom MotpInfo\n// after\nif (entry.getInfo() instanceof TotpInfo || entry.getInfo() instanceof HotpInfo) {\n    GoogleAuthInfo.getUri(entry);\n} else {\n    continue; // skip unsupported type\n}","handlingStrategy":"type-guard","validationCode":"if (!(info instanceof TotpInfo) && !(info instanceof HotpInfo)) {\n    throw new IllegalArgumentException(\"Only TOTP/HOTP entries can be exported\");\n}","typeGuard":"boolean exportable(VaultEntry e) {\n    return e.getInfo() instanceof TotpInfo || e.getInfo() instanceof HotpInfo;\n}","tryCatchPattern":"try {\n    uri = GoogleAuthInfo.getUri(entry);\n} catch (RuntimeException e) {\n    Log.w(TAG, \"Skipping non-exportable entry: \" + e.getMessage());\n}","preventionTips":["Filter entries to TotpInfo/HotpInfo before export","Handle fork-specific OtpInfo types separately","Wrap getUri per entry so one bad type skips rather than aborts"],"tags":["otp","internal-error","unsupported-type"],"backgroundTag":"internal-invariant-violation","analyzedSha":"d6f4e5925a97e4e91593f1542085eae03432a759","analyzedAt":"2026-09-08T00:46:31.111Z","contentChangedAt":"2026-09-08T00:46:31.111Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}