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
- As a CLI user: pass a valid protocol (http, https, tcp, udp, tls) — if you see this, also check NB_PROTOCOL
- 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
- Keep a single source of truth: validate with the same parser (expose.ParseProtocolType) you will convert with
- In the CLI flow, always run validateExposeFlags before toExposeProtocol
- When editing either the valid-set switch or the parser, update both in the same change
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
- unsupported protocol %q: must be http, https, tcp, udp, or t
- auth flags (--with-pin, --with-password, --with-user-groups)
- invalid port number: %s
- invalid port number: must be between 1 and 65535
- --with-external-port is not supported for %s protocol
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/dcf61dd4b4f6e6f8.
Report an issue: GitHub.