{"record":{"id":"2f9075a1e08a2dfb","repo":"felixse/FluentTerminal","slug":"userinfo-part-contains-parts-length-elements","errorCode":null,"errorMessage":"UserInfo part contains {parts.Length} elements.","messagePattern":"UserInfo part contains (.+?) elements\\.","errorType":"exception","errorClass":"FormatException","httpStatus":null,"severity":"error","filePath":"FluentTerminal.App.ViewModels/Profiles/SshConnectViewModel.cs","lineNumber":404,"sourceCode":"            IApplicationView applicationView, ITrayProcessCommunicationService trayProcessCommunicationService,\n            IFileSystemService fileSystemService, IApplicationDataContainer historyContainer)\n        {\n            var vm = new SshConnectViewModel(settingsService, applicationView, trayProcessCommunicationService,\n                fileSystemService)\n            {\n                Host = uri.Host,\n                UseMosh = MoshUriScheme.Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase)\n            };\n\n            if (uri.Port >= 0)\n                vm.SshPort = (ushort)uri.Port;\n\n            if (!string.IsNullOrEmpty(uri.UserInfo))\n            {\n                string[] parts = uri.UserInfo.Split(';');\n\n                if (parts.Length > 2)\n                    throw new FormatException($\"UserInfo part contains {parts.Length} elements.\");\n\n                vm.Username = HttpUtility.UrlDecode(parts[0]);\n\n                if (parts.Length > 1)\n                {\n                    // For now we are only interested in IdentityFile option\n                    Tuple<string, string> identityFileOption = ParseParams(parts[1], ',').FirstOrDefault(p =>\n                        string.Equals(p.Item1, IdentityFileOptionName, StringComparison.OrdinalIgnoreCase));\n\n                    vm.IdentityFile = identityFileOption?.Item2;\n                }\n            }\n\n            // ReSharper disable once ConstantConditionalAccessQualifier\n            string queryString = uri.Query?.Trim();\n\n            if (string.IsNullOrEmpty(queryString))\n            {","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/felixse/FluentTerminal/blob/ba83ec485eea8d8ee65825711731300bee2e76ed/FluentTerminal.App.ViewModels/Profiles/SshConnectViewModel.cs#L386-L422","documentation":"Thrown by SshConnectViewModel.ParseUri when uri.UserInfo split on ';' yields more than 2 parts. The URI scheme expects at most two semicolon-delimited segments: part[0] = username, part[1] = optional SSH options (e.g. IdentityFile=...). A third segment is treated as a malformed SSH/Mosh URI and raises FormatException.","triggerScenarios":"ParseUri is given an ssh:// or mosh:// URI whose UserInfo contains three or more ';' separators, e.g. ssh://user;opt1=x;opt2=y@host. The `parts.Length > 2` guard trips before any field is read.","commonSituations":"User pastes a malformed SSH URL with extra semicolons; an IdentityFile option value itself contains a semicolon (unencoded); a copy-paste from a config generator inserts extra segments; URL-encoding was not applied to special characters in UserInfo.","solutions":["Encode any ';' within username or option values as %3B before constructing the URI, or avoid ';' in values.","Restrict UserInfo to username only, or username plus a single options segment: ssh://user;IdentityFile=path@host.","Validate the URI format in the UI before calling ParseUri and show a helpful error."],"exampleFix":"// before\nstring[] parts = uri.UserInfo.Split(';');\nif (parts.Length > 2)\n    throw new FormatException($\"UserInfo part contains {parts.Length} elements.\");\n\n// after - tolerate extra segments by taking only the first two\nstring[] parts = uri.UserInfo.Split(';');\nif (parts.Length > 2)\n    throw new FormatException($\"UserInfo has {parts.Length} segments; expected at most user[;options].\");","handlingStrategy":"validation","validationCode":"// Validate UserInfo shape before ParseUri consumes it.\nif (!string.IsNullOrEmpty(uri.UserInfo))\n{\n    var segs = uri.UserInfo.Split(';');\n    if (segs.Length > 2) throw new FormatException($\"SSH UserInfo has {segs.Length} segments; expected user[;options].\");\n}","typeGuard":"static bool IsValidSshUserInfo(Uri uri) => string.IsNullOrEmpty(uri.UserInfo) || uri.UserInfo.Split(';').Length <= 2;","tryCatchPattern":"try { vm = SshConnectViewModel.ParseUri(uri, ...); }\ncatch (FormatException ex) { notifyUser($\"Invalid SSH link: {ex.Message}\"); }","preventionTips":["URL-encode ';' within UserInfo values as %3B.","Keep UserInfo to username plus at most one options segment.","Validate URI shape in the UI before parsing."],"tags":["uri-parsing","ssh","mosh","input-validation"],"backgroundTag":null,"analyzedSha":"ba83ec485eea8d8ee65825711731300bee2e76ed","analyzedAt":"2026-08-13T21:23:15.467Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}