{"record":{"id":"387d959739096072","repo":"netbirdio/netbird","slug":"local-port-forward-s-w","errorCode":null,"errorMessage":"local port forward %s: %w","messagePattern":"local port forward (.+?): %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/ssh.go","lineNumber":617,"sourceCode":"\t\t\treturn nil\n\t\t}\n\n\t\tvar exitMissingErr *ssh.ExitMissingError\n\t\tif errors.As(err, &exitMissingErr) {\n\t\t\tlog.Debugf(\"Remote terminal exited without exit status: %v\", err)\n\t\t\treturn nil\n\t\t}\n\n\t\treturn fmt.Errorf(\"open terminal: %w\", err)\n\t}\n\treturn nil\n}\n\n// startPortForwarding starts local and remote port forwarding based on command line flags\nfunc startPortForwarding(ctx context.Context, c *sshclient.Client, cmd *cobra.Command) error {\n\tfor _, forward := range localForwards {\n\t\tif err := parseAndStartLocalForward(ctx, c, forward, cmd); err != nil {\n\t\t\treturn fmt.Errorf(\"local port forward %s: %w\", forward, err)\n\t\t}\n\t}\n\n\tfor _, forward := range remoteForwards {\n\t\tif err := parseAndStartRemoteForward(ctx, c, forward, cmd); err != nil {\n\t\t\treturn fmt.Errorf(\"remote port forward %s: %w\", forward, err)\n\t\t}\n\t}\n\n\treturn nil\n}\n\n// parseAndStartLocalForward parses and starts a local port forward (-L)\nfunc parseAndStartLocalForward(ctx context.Context, c *sshclient.Client, forward string, cmd *cobra.Command) error {\n\tlocalAddr, remoteAddr, err := parsePortForwardSpec(forward)\n\tif err != nil {\n\t\treturn err\n\t}","sourceCodeStart":599,"sourceCodeEnd":635,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/ssh.go#L599-L635","documentation":"Returned by startPortForwarding when parseAndStartLocalForward rejects one -L/--local-forward spec before any listener starts. The wrap carries the exact spec, and the underlying error is either a parsePortForwardSpec failure (malformed colon structure) or validateDestinationPort rejecting the remote target (unparseable address, non-numeric port, port 0, or out-of-range port). Parsing stops at the first bad spec — later forwards are not attempted.","triggerScenarios":"`netbird ssh -L 8080:localhost peer` (two parts, second not a unix path), `-L 8080:host:0` (destination port 0), `-L 8080:host:99999` (out of range), `-L 8080:host:abc` (non-numeric), unbracketed IPv6 like `-L ::1:8080:host:80` (5 colon parts), or any spec with fewer than 2 / more than 4 colon-separated parts.","commonSituations":"Assuming OpenSSH's laxer parsing where trailing parts are ignored; forgetting the destination port; expecting port 0 to mean 'pick one' on the remote side; pasting forward lists where one entry lost a segment in shell quoting.","solutions":["Match one of the accepted forms: port:/path/to/socket, host:port:/path/to/socket, port:host:hostport, or host:port:host:hostport — destination must end in a unix path or a host:port with port 1-65535.","Put a concrete port on the destination; 0 is only valid for the local bind side, never the destination.","Bracket IPv6 hosts: -L [::1]:8080:host:80.","Quote the whole spec in the shell so colons survive intact, and check the wrapped message tail for which sub-validation (parse vs port) failed."],"exampleFix":"# before\nnetbird ssh -L 8080:peer1 peer1\n# -> start port forwarding: local port forward 8080:peer1: invalid port forward specification: ...\n\n# after\nnetbird ssh -L 8080:peer1:80 peer1","handlingStrategy":"validation","validationCode":"// mirror the CLI grammar for -L before building the command line\nfunc buildLocalForward(localPort int, remoteHost string, remotePort int) (string, error) {\n\tif localPort < 0 || remotePort < 1 || remotePort > 65535 {\n\t\treturn \"\", fmt.Errorf(\"ports out of range: local=%d remote=%d\", localPort, remotePort)\n\t}\n\tif remoteHost == \"\" {\n\t\treturn \"\", errors.New(\"remote host required\")\n\t}\n\treturn fmt.Sprintf(\"%d:%s:%d\", localPort, remoteHost, remotePort), nil\n}","typeGuard":"// matches port:host:port, host:port:host:port, or port:/unix/socket\nvar forwardSpecRe = regexp.MustCompile(`^([^:]+):([^:]+)(?::([^:]+))?(?::([^:]+))?$`)","tryCatchPattern":"if err := parseAndStartLocalForward(ctx, c, forward, cmd); err != nil {\n\t// wrapped cause is parse or port validation on this exact spec string;\n\t// surface spec + cause, keep other forwards running or abort per policy\n\tlog.Printf(\"skip local forward %q: %v\", forward, err)\n}","preventionTips":["Always end a TCP destination with :numeric-port; sockets must start with / or ./.","Bracket IPv6 local hosts and remember the remote side of the grammar is name/IPv4 only.","Generate specs from typed values (ints for ports), never by string concatenation of raw config.","Lint forward flags in wrapper scripts with a 2-4-part colon count check before exec."],"tags":["go","ssh","port-forwarding","validation","cli"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}