netbirdio/netbird · warning

unsupported protocol %q: must be http, https, tcp, udp, or t

Error message

unsupported protocol %q: must be http, https, tcp, udp, or tls

What it means

The --protocol flag value is not in the accepted set. isProtocolValid accepts exactly http, https, tcp, udp, tls (case-insensitive); the flag defaults to http. Rejected in validateExposeFlags before the daemon is contacted.

Source

Thrown at client/cmd/expose.go:111

// resolveExternalPort returns the effective external port, defaulting to the target port.
func resolveExternalPort(targetPort uint64) uint16 {
	if exposeExternalPort != 0 {
		return exposeExternalPort
	}
	return uint16(targetPort)
}

func validateExposeFlags(cmd *cobra.Command, portStr string) (uint64, error) {
	port, err := strconv.ParseUint(portStr, 10, 32)
	if err != nil {
		return 0, fmt.Errorf("invalid port number: %s", portStr)
	}
	if port == 0 || port > 65535 {
		return 0, fmt.Errorf("invalid port number: must be between 1 and 65535")
	}

	if !isProtocolValid(exposeProtocol) {
		return 0, fmt.Errorf("unsupported protocol %q: must be http, https, tcp, udp, or tls", exposeProtocol)
	}

	if isClusterProtocol(exposeProtocol) {
		if exposePin != "" || exposePassword != "" || len(exposeUserGroups) > 0 {
			return 0, fmt.Errorf("auth flags (--with-pin, --with-password, --with-user-groups) are not supported for %s protocol", exposeProtocol)
		}
	} else if cmd.Flags().Changed("with-external-port") {
		return 0, fmt.Errorf("--with-external-port is not supported for %s protocol", exposeProtocol)
	}

	if exposePin != "" && !pinRegexp.MatchString(exposePin) {
		return 0, fmt.Errorf("invalid pin: must be exactly 6 digits")
	}

	if cmd.Flags().Changed("with-password") && exposePassword == "" {
		return 0, fmt.Errorf("password cannot be empty")
	}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. Use one of: http, https, tcp, udp, tls (lower or upper case)
  2. For gRPC, websocket, or other raw stream services, expose as tcp or tls
  3. Check for a stray NB_PROTOCOL env var: `echo $NB_PROTOCOL` and unset it if wrong

Example fix

# before
netbird expose --protocol websocket 8080

# after
netbird expose --protocol tcp 8080
Defensive patterns

Strategy: validation

Validate before calling

valid := map[string]bool{"http": true, "https": true, "tcp": true, "udp": true, "tls": true}
if !valid[strings.ToLower(proto)] {
	log.Fatalf("unsupported protocol %q; use http, https, tcp, udp, or tls", proto)
}

Type guard

func isValidExposeProtocol(p string) bool {
	switch strings.ToLower(p) {
	case "http", "https", "tcp", "udp", "tls":
		return true
	default:
		return false
	}
}

Prevention

When it happens

Trigger: `--protocol websocket`, `--protocol grpc`, `--protocol httsp` (typo), or `--protocol=` (empty). Also reachable when the NB_PROTOCOL environment variable carries an invalid value, because SetFlagsFromEnvVars maps NB_PROTOCOL onto the flag.

Common situations: Assuming any L7 protocol name is supported; typos; an exported NB_PROTOCOL from earlier experiments overriding the intended value.

Understand the failure class

Related errors


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/2437837110278662. Report an issue: GitHub.