netbirdio/netbird · error
listen_port is not supported for HTTP services
Error message
listen_port is not supported for HTTP services
What it means
Returned by Service.Validate() -> validateHTTPMode when the service mode resolves to "http" (an empty Mode is defaulted to http by Validate()) and Service.ListenPort is non-zero. HTTP reverse-proxy services are routed by hostname on the proxy's shared listeners, so a dedicated listen port has no meaning there; listen ports belong to the L4 modes (required for tls, optional-but-routed for tcp/udp). The check fails fast at API/store time so the invalid combination never reaches the proxy config push.
Source
Thrown at management/internals/modules/reverseproxy/service/service.go:915
}
if s.Mode != "" && s.Mode != ModeHTTP {
return fmt.Errorf("private services only support HTTP mode, got %q", s.Mode)
}
if len(s.AccessGroups) == 0 {
return errors.New("private services require at least one access group")
}
if s.Auth.BearerAuth != nil && s.Auth.BearerAuth.Enabled {
return errors.New("private services cannot enable bearer auth (SSO): NetBird-only access and SSO are mutually exclusive")
}
return nil
}
func (s *Service) validateHTTPMode() error {
if s.Domain == "" {
return errors.New("service domain is required")
}
if s.ListenPort != 0 {
return errors.New("listen_port is not supported for HTTP services")
}
return s.validateHTTPTargets()
}
func (s *Service) validateTCPUDPMode() error {
if s.Domain == "" {
return errors.New("domain is required for TCP/UDP services (used for cluster derivation)")
}
if s.isAuthEnabled() {
return errors.New("auth is not supported for TCP/UDP services")
}
if len(s.Targets) != 1 {
return errors.New("TCP/UDP services must have exactly one target")
}
if s.Mode == ModeUDP && s.Targets[0].ProxyProtocol {
return errors.New("proxy_protocol is not supported for UDP services")
}
return s.validateL4Target(s.Targets[0])View on GitHub (pinned to 93e97f4bf1)
Solutions
- Remove listen_port (omit the field or set it to 0) from the HTTP service definition.
- If you actually want port-based routing, change mode to "tcp" or "udp" and keep the port.
- If you are terminating TLS on a dedicated port with SNI routing, use mode "tls" which requires listen_port.
- If a UI/automation always sends the field, patch it to omit listen_port when mode is http.
Example fix
// before
{
"name": "my-app",
"mode": "http",
"domain": "netbird.example.com",
"listen_port": 8443,
"targets": [...]
}
// after
{
"name": "my-app",
"mode": "http",
"domain": "netbird.example.com",
"targets": [...]
} Defensive patterns
Strategy: validation
Validate before calling
func checkHTTPListenPort(mode string, listenPort uint16) error {
if mode == "" {
mode = "http"
}
if mode == "http" && listenPort != 0 {
return fmt.Errorf("listen_port %d not allowed for http service", listenPort)
}
return nil
} Type guard
func isHTTPModeSafe(mode string, listenPort uint16) bool {
if mode == "" {
mode = "http"
}
return mode != "http" || listenPort == 0
} Try / catch
if err := svc.Validate(); err != nil {
if strings.Contains(err.Error(), "listen_port is not supported for HTTP") {
// config bug, fix payload - never retry
}
return respondBadRequest(err)
} Prevention
- Mode-specific payload builders: only attach listen_port when mode is tcp, udp, or tls.
- Treat validation errors from Validate() as permanent 400s - never retry them.
- Add a schema/fixture test that round-trips each mode's payload through Validate().
When it happens
Trigger: POST/PUT of a reverse-proxy service with mode "http" or mode omitted and a non-zero listen_port in the payload; updating an existing TCP service to mode http without clearing listen_port; a UI or Terraform-like module that always serializes a listen_port field (e.g. 443) even for HTTP services.
Common situations: Copying a TCP/TLS service JSON as a template for a new HTTP service and forgetting to delete listen_port. Frontend forms that submit every field with a default port value. Migrating a service between modes during a restructure and leaving stale fields behind.
Related errors
- service domain is required
- domain is required for TCP/UDP services (used for cluster de
- auth is not supported for TCP/UDP services
- TCP/UDP services must have exactly one target
- listen_port is required for TLS services
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/73dad979c48c06d9.
Report an issue: GitHub.