{"record":{"id":"1d9c9a5676bc3017","repo":"BeyondDimension/SteamTools","slug":"import-only-supports-otpauth","errorCode":null,"errorMessage":"Import only supports otpauth://","messagePattern":"Import only supports otpauth://","errorType":"exception","errorClass":"ApplicationException","httpStatus":null,"severity":"warning","filePath":"src/BD.WTTS.Client.Plugins.Authenticator/UI/ViewModels/AuthenticatorImportPageViewModel.cs","lineNumber":266,"sourceCode":"                {\n                    continue;\n                }\n\n                // bug if there is a hash before ?\n                var hash = line.IndexOf(\"#\", StringComparison.Ordinal);\n                var qm = line.IndexOf(\"?\", StringComparison.Ordinal);\n                if (hash != -1 && hash < qm)\n                {\n                    line = $\"{line.Substring(0, hash)}%23{line[(hash + 1)..]}\";\n                }\n\n                // parse and validate URI\n                var uri = new Uri(line);\n\n                // we only support \"otpauth\"\n                if (uri.Scheme != \"otpauth\")\n                {\n                    throw new ApplicationException(\"Import only supports otpauth://\");\n                }\n\n                // we only support totp (not hotp)\n                if (uri.Host != \"totp\" && uri.Host != \"hotp\")\n                {\n                    throw new ApplicationException(\"Import only supports otpauth://totp/ or otpauth://hotp/\");\n                }\n\n                // get the label and optional issuer\n                string issuer = string.Empty;\n                string label = string.IsNullOrEmpty(uri.LocalPath) == false\n                    ? uri.LocalPath[1..]\n                    : string.Empty; // skip past initial /\n                int p = label.IndexOf(\":\", StringComparison.Ordinal);\n                if (p != -1)\n                {\n                    issuer = label.Substring(0, p);\n                    label = label[(p + 1)..];","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/BeyondDimension/SteamTools/blob/c16ffa08e03b192d23ada290c4969e77f9201f3d/src/BD.WTTS.Client.Plugins.Authenticator/UI/ViewModels/AuthenticatorImportPageViewModel.cs#L248-L284","documentation":"Thrown during authenticator import when a parsed URI's scheme is not 'otpauth'. The importer only understands the otpauth:// URI format (RFC 6238-style), so any other scheme (http, https, steam://, bare text) is rejected at the scheme check before host/path validation.","triggerScenarios":"Importing a line/QR content whose URI scheme is not otpauth — e.g. a plain URL, a 'steam://' link, a google otpauth typo, or a non-URI string that happened to parse as a Uri with a different scheme.","commonSituations":"User scanned the wrong QR code (a URL instead of an otpauth code); export file from another manager uses a different scheme; copy-paste included extra prefix text; legacy 'otpauth' typos like 'otp-auth://' or 'http://otpauth'.","solutions":["Re-export from the source authenticator as an otpauth:// URI (standard QR format).","Strip any leading/trailing whitespace or stray prefix from the imported line before parsing.","If migrating from a tool using a different format, convert each entry to otpauth:// first.","Validate the scheme in the UI and show a friendly message instead of throwing."],"exampleFix":"// before\nif (uri.Scheme != \"otpauth\")\n    throw new ApplicationException(\"Import only supports otpauth://\");\n\n// after: friendly, localized validation\nif (uri.Scheme != \"otpauth\")\n    throw new ArgumentException(string.Format(Strings.Import_UnsupportedScheme, uri.Scheme));","handlingStrategy":"validation","validationCode":"// Validate scheme before parsing the entry.\nstatic bool IsOtpAuthUri(string line)\n{\n    if (string.IsNullOrWhiteSpace(line)) return false;\n    try { return new Uri(line.Trim()).Scheme.Equals(\"otpauth\", StringComparison.OrdinalIgnoreCase); }\n    catch (UriFormatException) { return false; }\n}\n\nif (!IsOtpAuthUri(line))\n    errors.Add(($\"Line {n}: not an otpauth:// URI.\", line));","typeGuard":"bool IsOtpAuth(string line) => Uri.TryCreate(line?.Trim(), UriKind.Absolute, out var u) && u.Scheme == \"otpauth\";","tryCatchPattern":"try { ParseAuthenticator(line); }\ncatch (ApplicationException ex) when (ex.Message == \"Import only supports otpauth://\")\n{\n    importErrors.Add(($\"Unsupported URI scheme (line {n}).\", line));\n    continue; // skip entry, keep importing the rest\n}","preventionTips":["Trim and schema-check each line in the import UI before parsing; show inline errors.","Accept drag-drop of files but pre-filter to otpauth:// lines.","Provide a template/preview of a valid otpauth URI next to the import field.","Differentiate 'wrong scheme' from 'wrong type' in the user-facing message."],"tags":["authenticator","import","validation","uri"],"backgroundTag":null,"analyzedSha":"c16ffa08e03b192d23ada290c4969e77f9201f3d","analyzedAt":"2026-08-13T11:52:20.410Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}