netbirdio/netbird · warning

invalid protocol: %w

Error message

invalid protocol: %w

What it means

toExposeProtocol wraps the error from expose.ParseProtocolType: the protocol string is not http, https, tcp, udp, or tls. In the normal CLI flow this is effectively unreachable, because exposeFn calls validateExposeFlags first and isProtocolValid rejects the exact same set before any RPC; it fires only when toExposeProtocol runs without that pre-validation (programmatic use, a refactor dropping the validate call, or future drift between the two whitelists).

Source

Thrown at client/cmd/expose.go:218

		req.ListenPort = uint32(resolveExternalPort(port))
	}

	stream, err := client.ExposeService(ctx, req)
	if err != nil {
		return fmt.Errorf("expose service: %v", status.Convert(err).Message())
	}

	if err := handleExposeReady(cmd, stream, port); err != nil {
		return err
	}

	return waitForExposeEvents(cmd, ctx, stream)
}

func toExposeProtocol(exposeProtocol string) (proto.ExposeProtocol, error) {
	p, err := expose.ParseProtocolType(exposeProtocol)
	if err != nil {
		return 0, fmt.Errorf("invalid protocol: %w", err)
	}

	switch p {
	case expose.ProtocolHTTP:
		return proto.ExposeProtocol_EXPOSE_HTTP, nil
	case expose.ProtocolHTTPS:
		return proto.ExposeProtocol_EXPOSE_HTTPS, nil
	case expose.ProtocolTCP:
		return proto.ExposeProtocol_EXPOSE_TCP, nil
	case expose.ProtocolUDP:
		return proto.ExposeProtocol_EXPOSE_UDP, nil
	case expose.ProtocolTLS:
		return proto.ExposeProtocol_EXPOSE_TLS, nil
	default:
		return 0, fmt.Errorf("unhandled protocol type: %d", p)
	}
}

View on GitHub (pinned to 93e97f4bf1)

Solutions

  1. As a CLI user: pass a valid protocol (http, https, tcp, udp, tls) — if you see this, also check NB_PROTOCOL
  2. As a developer: run validateExposeFlags (or an equivalent whitelist check) before calling toExposeProtocol, keeping both lists in sync

Example fix

// before
proto, err := toExposeProtocol(exposeProtocol) // may fail

// after
if _, err := validateExposeFlags(cmd, portStr); err != nil {
	return err
}
proto, err := toExposeProtocol(exposeProtocol)
Defensive patterns

Strategy: validation

Validate before calling

if _, err := expose.ParseProtocolType(protoFlag); err != nil {
	log.Fatalf("%v; use http, https, tcp, udp, or tls", err)
}

Type guard

func isParseableProtocol(p string) bool {
	_, err := expose.ParseProtocolType(p)
	return err == nil
}

Prevention

When it happens

Trigger: Calling toExposeProtocol directly from code without running validateExposeFlags; a code path that bypasses exposeFn; the accepted set in isProtocolValid diverging from ParseProtocolType after an edit.

Common situations: Reusing the CLI helper from another tool or test; refactors that reorder validation; a contributor extending one switch but not the other.

Related errors


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