{"record":{"id":"1e90bc5406bbf885","repo":"netbirdio/netbird","slug":"port-0-is-not-valid-for-destination-address","errorCode":null,"errorMessage":"port 0 is not valid for destination address","messagePattern":"port 0 is not valid for destination address","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/ssh.go","lineNumber":693,"sourceCode":"// 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\n// parsePortForwardSpec parses port forward specifications like \"8080:localhost:80\" or \"[::1]:8080:localhost:80\".\n// Also supports Unix sockets like \"8080:/tmp/socket\" or \"127.0.0.1:8080:/tmp/socket\".\nfunc parsePortForwardSpec(spec string) (string, string, error) {\n\t// Support formats:\n\t// port:host:hostport  -> localhost:port -> host:hostport\n\t// host:port:host:hostport  -> host:port -> host:hostport\n\t// [host]:port:host:hostport -> [host]:port -> host:hostport\n\t// port:unix_socket_path -> localhost:port -> unix_socket_path\n\t// host:port:unix_socket_path -> host:port -> unix_socket_path","sourceCodeStart":675,"sourceCodeEnd":711,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/ssh.go#L675-L711","documentation":"Returned by validateDestinationPort when the destination port parses as an integer but is exactly 0. Port 0 on a bind address means 'let the OS choose', which is meaningful only for the listening side; a destination must identify a concrete service, so 0 is rejected for the endpoint the forward connects to. This is a sentinel error with no %w wrap — the message is final.","triggerScenarios":"`-L 8080:host:0` (remote destination port 0) surfacing as `invalid remote address: port 0 is not valid for destination address`; `-R 9000:localhost:0` (local endpoint port 0) surfacing as `invalid local address: port 0 ...`. Note `-L 0:host:80` is different: that is the local bind port and is not checked by this validator.","commonSituations":"Reusing an OpenSSH pattern where a zero remote port triggers dynamic/SOCKS-style allocation (not supported here); config templates with PORT=0 meaning 'unassigned'; scripts defaulting unset ports to 0.","solutions":["Put a real service port on the destination side: 1-65535.","If 0 was meant for the local listener, move it to the bind position (-L 0:host:80) — that side is not port-validated by this function.","In templates/scripts, fail on unset ports instead of defaulting to 0: ${PORT:?port required}."],"exampleFix":"# before\nnetbird ssh -L 8080:dbhost:0 peer1\n# -> invalid remote address: port 0 is not valid for destination address\n\n# after\nnetbird ssh -L 8080:dbhost:5432 peer1","handlingStrategy":"validation","validationCode":"// reject zero ports before they ever reach a spec\nif port == 0 {\n\treturn fmt.Errorf(\"port 0 is only valid on the bind side; destination %q needs 1-65535\", target)\n}\nspec := fmt.Sprintf(\"%d:%s:%d\", bindPort, host, port)","typeGuard":"func isValidDestinationPort(n int) bool { return n >= 1 && n <= 65535 }","tryCatchPattern":"if port == 0 {\n\t// sentinel, no wrap: handle by re-prompting for the real service port;\n\t// do not 'fix' it to a guessed default silently\n}","preventionTips":["Never default unset ports to 0; fail at config load (${PORT:?required}) instead.","Remember the asymmetry: 0 may appear on the bind side (-L 0:host:80), never on the destination side.","Encode 'destination port must be 1-65535' as a shared validation in your spec builder so all scripts inherit it."],"tags":["go","ssh","validation","port","cli"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}