felixse/FluentTerminal · error · FormatException
UserInfo part contains {parts.Length} elements.
Error message
UserInfo part contains {parts.Length} elements. What it means
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.
Source
Thrown at FluentTerminal.App.ViewModels/Profiles/SshConnectViewModel.cs:404
IApplicationView applicationView, ITrayProcessCommunicationService trayProcessCommunicationService,
IFileSystemService fileSystemService, IApplicationDataContainer historyContainer)
{
var vm = new SshConnectViewModel(settingsService, applicationView, trayProcessCommunicationService,
fileSystemService)
{
Host = uri.Host,
UseMosh = MoshUriScheme.Equals(uri.Scheme, StringComparison.OrdinalIgnoreCase)
};
if (uri.Port >= 0)
vm.SshPort = (ushort)uri.Port;
if (!string.IsNullOrEmpty(uri.UserInfo))
{
string[] parts = uri.UserInfo.Split(';');
if (parts.Length > 2)
throw new FormatException($"UserInfo part contains {parts.Length} elements.");
vm.Username = HttpUtility.UrlDecode(parts[0]);
if (parts.Length > 1)
{
// For now we are only interested in IdentityFile option
Tuple<string, string> identityFileOption = ParseParams(parts[1], ',').FirstOrDefault(p =>
string.Equals(p.Item1, IdentityFileOptionName, StringComparison.OrdinalIgnoreCase));
vm.IdentityFile = identityFileOption?.Item2;
}
}
// ReSharper disable once ConstantConditionalAccessQualifier
string queryString = uri.Query?.Trim();
if (string.IsNullOrEmpty(queryString))
{View on GitHub (pinned to ba83ec485e)
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.
Example fix
// before
string[] parts = uri.UserInfo.Split(';');
if (parts.Length > 2)
throw new FormatException($"UserInfo part contains {parts.Length} elements.");
// after - tolerate extra segments by taking only the first two
string[] parts = uri.UserInfo.Split(';');
if (parts.Length > 2)
throw new FormatException($"UserInfo has {parts.Length} segments; expected at most user[;options]."); Defensive patterns
Strategy: validation
Validate before calling
// Validate UserInfo shape before ParseUri consumes it.
if (!string.IsNullOrEmpty(uri.UserInfo))
{
var segs = uri.UserInfo.Split(';');
if (segs.Length > 2) throw new FormatException($"SSH UserInfo has {segs.Length} segments; expected user[;options].");
} Type guard
static bool IsValidSshUserInfo(Uri uri) => string.IsNullOrEmpty(uri.UserInfo) || uri.UserInfo.Split(';').Length <= 2; Try / catch
try { vm = SshConnectViewModel.ParseUri(uri, ...); }
catch (FormatException ex) { notifyUser($"Invalid SSH link: {ex.Message}"); } Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- UserInfo part contains ${parts.Length} elements.
- Invalid link.
- Root node was not a dictionary.
- Color node was not a dictionary
AI-assisted analysis of felixse/FluentTerminal@ba83ec485e (2026-08-13).
Data as JSON: /api/errors/2f9075a1e08a2dfb.
Report an issue: GitHub.