netbirdio/netbird · error
invalid port forward specification: %s (expected format: [lo
Error message
invalid port forward specification: %s (expected format: [local_host:]local_port:remote_host:remote_port or [local_host:]local_port:unix_socket)
What it means
Returned by parseTwoPartForwardSpec when the spec has exactly two colon parts but the second is not a unix socket path (does not start with / or ./). Two-part specs are only legal as `port:/abs/path` or `port:./rel/path`; a two-part `port:host` form has no meaning because the remote port would be missing, so it is rejected with the full expected-format message.
Source
Thrown at client/cmd/ssh.go:741
case 2:
return parseTwoPartForwardSpec(parts, spec)
case 3:
return parseThreePartForwardSpec(parts)
case 4:
return parseFourPartForwardSpec(parts)
default:
return "", "", fmt.Errorf("invalid port forward specification: %s", spec)
}
}
// parseTwoPartForwardSpec handles "port:unix_socket" format.
func parseTwoPartForwardSpec(parts []string, spec string) (string, string, error) {
if isUnixSocket(parts[1]) {
localAddr := "localhost:" + parts[0]
remoteAddr := parts[1]
return localAddr, remoteAddr, nil
}
return "", "", fmt.Errorf("invalid port forward specification: %s (expected format: [local_host:]local_port:remote_host:remote_port or [local_host:]local_port:unix_socket)", spec)
}
// parseThreePartForwardSpec handles "port:host:hostport" or "host:port:unix_socket" formats.
func parseThreePartForwardSpec(parts []string) (string, string, error) {
if isUnixSocket(parts[2]) {
localHost := normalizeLocalHost(parts[0])
localAddr := localHost + ":" + parts[1]
remoteAddr := parts[2]
return localAddr, remoteAddr, nil
}
localAddr := "localhost:" + parts[0]
remoteAddr := parts[1] + ":" + parts[2]
return localAddr, remoteAddr, nil
}
// parseFourPartForwardSpec handles "host:port:host:hostport" format.
func parseFourPartForwardSpec(parts []string) (string, string, error) {
localHost := normalizeLocalHost(parts[0])View on GitHub (pinned to 93e97f4bf1)
Solutions
- If the target is TCP, write the full 3-part form: port:host:remote_port (e.g., 8080:localhost:80).
- If the target is a unix socket, keep the path absolute (8080:/run/svc.sock) or ./-prefixed so isUnixSocket recognizes it.
- Avoid guessing defaults — every destination needs its explicit port or path.
Example fix
# before netbird ssh -L 8080:localhost peer1 # -> invalid port forward specification: 8080:localhost (expected format: [local_host:]local_port:remote_host:remote_port or [local_host:]local_port:unix_socket) # after netbird ssh -L 8080:localhost:80 peer1 # or, for a socket: netbird ssh -L 8080:/var/run/service.sock peer1
Defensive patterns
Strategy: validation
Validate before calling
// two-part specs are ONLY port + unix socket
parts := strings.Split(spec, ":")
if len(parts) == 2 {
if !strings.HasPrefix(parts[1], "/") && !strings.HasPrefix(parts[1], "./") {
return fmt.Errorf("2-part spec %q needs a socket path as target or a 3rd part (host:port)", spec)
}
} Type guard
func isSocketTarget(s string) bool { return strings.HasPrefix(s, "/") || strings.HasPrefix(s, "./") } Try / catch
if len(parts) == 2 && !isUnixSocket(parts[1]) {
// host-only second part: auto-expand to 3 parts with the known service port
// or reject — never guess silently in production paths
} Prevention
- Encode the rule: two colon parts == socket forward, nothing else.
- When shortening specs in docs/scripts, always keep host:port together on the destination side.
- Keep socket paths absolute (/run/svc.sock) so the prefix check recognizes them.
- Lint configs for 2-part forwards whose second part lacks a leading slash.
When it happens
Trigger: `-L 8080:localhost peer` (host without port, hoping the default applies), `-R 9000:service peer`, or `-L 8080:socket peer` where the intended socket path lost its leading slash. Any 2-part spec whose second element fails the isUnixSocket prefix check.
Common situations: Abbreviating to host-only when the remote port is 'obvious' (db -> 5432); socket paths passed relative without ./ ; typos dropping the port after editing a longer spec down.
Related errors
- start port forwarding: %w
- local port forward %s: %w
- remote port forward %s: %w
- invalid remote address: %w
- invalid local address: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/0723e0fe1f702f01.
Report an issue: GitHub.