{"record":{"id":"5bea8683b0fb3fbb","repo":"wavetermdev/waveterm","slug":"invalid-format-of-user-host-argument","errorCode":null,"errorMessage":"invalid format of user@host argument","messagePattern":"invalid format of user@host argument","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/remote/connutil.go","lineNumber":34,"sourceCode":"\t\"strings\"\n\t\"text/template\"\n\t\"time\"\n\n\t\"github.com/wavetermdev/waveterm/pkg/blocklogger\"\n\t\"github.com/wavetermdev/waveterm/pkg/genconn\"\n\t\"github.com/wavetermdev/waveterm/pkg/util/iterfn\"\n\t\"github.com/wavetermdev/waveterm/pkg/util/shellutil\"\n\t\"github.com/wavetermdev/waveterm/pkg/wavebase\"\n\t\"github.com/wavetermdev/waveterm/pkg/wconfig\"\n\t\"golang.org/x/crypto/ssh\"\n)\n\nvar userHostRe = regexp.MustCompile(`^([a-zA-Z0-9][a-zA-Z0-9._@\\\\-]*@)?([a-zA-Z0-9][a-zA-Z0-9.-]*)(?::([0-9]+))?$`)\n\nfunc ParseOpts(input string) (*SSHOpts, error) {\n\tm := userHostRe.FindStringSubmatch(input)\n\tif m == nil {\n\t\treturn nil, fmt.Errorf(\"invalid format of user@host argument\")\n\t}\n\tremoteUser, remoteHost, remotePort := m[1], m[2], m[3]\n\tremoteUser = strings.Trim(remoteUser, \"@\")\n\n\treturn &SSHOpts{SSHHost: remoteHost, SSHUser: remoteUser, SSHPort: remotePort}, nil\n}\n\nfunc normalizeOs(os string) string {\n\tos = strings.ToLower(strings.TrimSpace(os))\n\treturn os\n}\n\nfunc normalizeArch(arch string) string {\n\tarch = strings.ToLower(strings.TrimSpace(arch))\n\tswitch arch {\n\tcase \"x86_64\", \"amd64\":\n\t\tarch = \"x64\"\n\tcase \"arm64\", \"aarch64\":","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/remote/connutil.go#L16-L52","documentation":"ParseOpts parses an SSH 'user@host' (optionally 'host' or 'user@host:port') string into SSHOpts using the userHostRe regular expression. This error is returned when the input string does not match the pattern, i.e. it is not a syntactically valid user@host argument. It is a pure input-validation error thrown before any network activity.","triggerScenarios":"Calling ParseOpts with a string failing userHostRe: empty string, leading/trailing whitespace, IPv6 address ([::1] or ::1), hostname with protocol prefix (ssh://host), username starting with non-alphanumeric, port with non-digits, or multiple '@' placed incorrectly.","commonSituations":"Users pasting 'ssh user@host' with the 'ssh ' prefix into connection settings; IPv6 targets; hostnames with underscores or unicode characters; trailing slashes or spaces copied from terminal output; invalid entries stored in saved connection configs validated by validateConnectionName or applySSHOverrides.","solutions":["Trim whitespace and remove any 'ssh://' or 'ssh ' prefix from the input before calling ParseOpts.","Use a plain hostname or user@host[:port] form; for IPv6, use resolvable DNS names or preprocess the address outside this parser.","Validate the string against a copy of userHostRe in the caller before invoking, to give a better error message.","If a username contains characters outside [a-zA-Z0-9._@\\-], restructure the input or extend the regex in connutil.go."],"exampleFix":"// before\nopts, err := connutil.ParseOpts(\"ssh user@host\") // invalid: 'ssh ' prefix\n// after\ninput := strings.TrimSpace(strings.TrimPrefix(strings.TrimPrefix(input, \"ssh://\"), \"ssh \"))\nopts, err := connutil.ParseOpts(input)","handlingStrategy":"validation","validationCode":"var userHostRe = regexp.MustCompile(`^([a-zA-Z0-9][a-zA-Z0-9._@\\\\-]*@)?([a-zA-Z0-9][a-zA-Z0-9.-]*)(?::([0-9]+))?$`)\nfunc validUserHost(s string) bool { return userHostRe.MatchString(strings.TrimSpace(s)) }\n// call connutil.ParseOpts only if validUserHost(input)","typeGuard":null,"tryCatchPattern":"opts, err := connutil.ParseOpts(input)\nif err != nil {\n    return fmt.Errorf(\"connection target %q is not valid user@host[:port]; got: %w\", input, err)\n}","preventionTips":["Trim whitespace and strip 'ssh://' / 'ssh ' prefixes from user input before parsing.","Do not paste full ssh command lines into connection fields; store only user@host:port.","Validate saved connection strings at config-load time so bad entries surface early.","Prefer DNS hostnames over raw IPv6 literals for compatibility with the regex."],"tags":["go","validation","ssh","parsing"],"backgroundTag":"invalid-ssh-host-format","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}