{"record":{"id":"160e683872f35d96","repo":"netbirdio/netbird","slug":"parse-address-s-w","errorCode":null,"errorMessage":"parse address %s: %w","messagePattern":"parse address (.+?): %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/ssh.go","lineNumber":684,"sourceCode":"\t\tif err := c.RemotePortForward(ctx, remoteAddr, localAddr); err != nil && !errors.Is(err, context.Canceled) {\n\t\t\tcmd.Printf(\"Remote port forward error: %v\\n\", err)\n\t\t}\n\t}()\n\n\treturn nil\n}\n\n// validateDestinationPort checks that the destination address has a valid port.\n// Port 0 is only valid for bind addresses (where the OS picks an available port),\n// not for destination addresses where we need to connect.\nfunc validateDestinationPort(addr string) error {\n\tif strings.HasPrefix(addr, \"/\") || strings.HasPrefix(addr, \"./\") {\n\t\treturn nil\n\t}\n\n\t_, portStr, err := net.SplitHostPort(addr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"parse address %s: %w\", addr, err)\n\t}\n\n\tport, err := strconv.Atoi(portStr)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"invalid port %s: %w\", portStr, err)\n\t}\n\n\tif port == 0 {\n\t\treturn fmt.Errorf(\"port 0 is not valid for destination address\")\n\t}\n\n\tif port < 0 || port > 65535 {\n\t\treturn fmt.Errorf(\"port %d out of range (1-65535)\", port)\n\t}\n\n\treturn nil\n}\n","sourceCodeStart":666,"sourceCodeEnd":702,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/ssh.go#L666-L702","documentation":"Produced inside validateDestinationPort when net.SplitHostPort cannot split the destination address into host and port. SplitHostPort errors on a missing port (`address host: missing port in address`), on too many colons for an unbracketed IPv6 literal (`too many colons in address`), and on malformed bracket forms. Addresses starting with / or ./ are exempted (unix sockets) before this check.","triggerScenarios":"Destination like `dbhost` (no port at all), `::1:8080` (unbracketed IPv6 plus port — SplitHostPort cannot disambiguate), `[fe80::1]` without a port, or a stray bracket form like `[host:80`. Reached from -L via `invalid remote address: ...` and from -R via `invalid local address: ...`.","commonSituations":"Omitting the port when shortening specs; pasting IPv6 addresses without brackets; specs assembled by string concatenation where the port segment came out empty; targets meant to be sockets but missing the leading slash so they parse as hostnames.","solutions":["Add the :port suffix so the destination is host:port, e.g., dbhost:5432.","Bracket IPv6 hosts before appending the port: [2001:db8::1]:443.","If the destination is a unix socket, give it a / or ./ prefix so it bypasses this check.","For empty ports from variables, default them explicitly: ${PORT:-80}."],"exampleFix":"# before\nnetbird ssh -L 8080:2001:db8::1 peer1\n# -> invalid remote address: parse address 2001:db8::1: address 2001:db8::1: too many colons in address\n\n# after\nnetbird ssh -L 8080:'[2001:db8::1]:443' peer1","handlingStrategy":"validation","validationCode":"// pre-split before composing/running the CLI\nhost, portStr, err := net.SplitHostPort(candidate)\nif err != nil {\n\tif strings.Contains(err.Error(), \"too many colons\") {\n\t\t// unbracketed IPv6: re-emit as [v6]:port\n\t\tcandidate = fmt.Sprintf(\"[%s]:%s\", host, portStr) // adjust per your data shape\n\t} else {\n\t\treturn fmt.Errorf(\"add :port to destination %q\", candidate)\n\t}\n}","typeGuard":"// true when the string is a parseable host:port or a unix socket path\nfunc isHostPortOrSocket(s string) bool {\n\tif strings.HasPrefix(s, \"/\") || strings.HasPrefix(s, \"./\") {\n\t\treturn true\n\t}\n\t_, _, err := net.SplitHostPort(s)\n\treturn err == nil\n}","tryCatchPattern":"if _, _, err := net.SplitHostPort(addr); err != nil {\n\t// err is *net.AddrError with Err in {\"missing port in address\", \"too many colons in address\"};\n\t// branch on it: prompt for a port vs demand brackets\n}","preventionTips":["Always bracket IPv6 literals in any host:port string you build: [2001:db8::1]:443.","Never emit a destination without a port; make the port a required typed field upstream of string building.","Reuse net.SplitHostPort in your validators instead of manual strings.LastIndex logic — same semantics as the CLI.","Unit-test spec builders with IPv6 fixtures; they are the canonical source of 'too many colons'."],"tags":["go","ssh","validation","ipv6","network"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}