{"record":{"id":"e0b4eecf9f0f61be","repo":"netbirdio/netbird","slug":"with-external-port-is-not-supported-for-s-proto","errorCode":null,"errorMessage":"--with-external-port is not supported for %s protocol","messagePattern":"--with-external-port is not supported for (.+?) protocol","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"client/cmd/expose.go","lineNumber":119,"sourceCode":"func validateExposeFlags(cmd *cobra.Command, portStr string) (uint64, error) {\n\tport, err := strconv.ParseUint(portStr, 10, 32)\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"invalid port number: %s\", portStr)\n\t}\n\tif port == 0 || port > 65535 {\n\t\treturn 0, fmt.Errorf(\"invalid port number: must be between 1 and 65535\")\n\t}\n\n\tif !isProtocolValid(exposeProtocol) {\n\t\treturn 0, fmt.Errorf(\"unsupported protocol %q: must be http, https, tcp, udp, or tls\", exposeProtocol)\n\t}\n\n\tif isClusterProtocol(exposeProtocol) {\n\t\tif exposePin != \"\" || exposePassword != \"\" || len(exposeUserGroups) > 0 {\n\t\t\treturn 0, fmt.Errorf(\"auth flags (--with-pin, --with-password, --with-user-groups) are not supported for %s protocol\", exposeProtocol)\n\t\t}\n\t} else if cmd.Flags().Changed(\"with-external-port\") {\n\t\treturn 0, fmt.Errorf(\"--with-external-port is not supported for %s protocol\", exposeProtocol)\n\t}\n\n\tif exposePin != \"\" && !pinRegexp.MatchString(exposePin) {\n\t\treturn 0, fmt.Errorf(\"invalid pin: must be exactly 6 digits\")\n\t}\n\n\tif cmd.Flags().Changed(\"with-password\") && exposePassword == \"\" {\n\t\treturn 0, fmt.Errorf(\"password cannot be empty\")\n\t}\n\n\tif cmd.Flags().Changed(\"with-user-groups\") && len(exposeUserGroups) == 0 {\n\t\treturn 0, fmt.Errorf(\"user groups cannot be empty\")\n\t}\n\n\treturn port, nil\n}\n\nfunc isProtocolValid(exposeProtocol string) bool {","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/expose.go#L101-L137","documentation":"--with-external-port was explicitly set while --protocol is http or https. cmd.Flags().Changed(\"with-external-port\") is true, but the flag only has meaning for cluster (L4) protocols: the request builder sets req.ListenPort from resolveExternalPort only when isClusterProtocol is true. HTTP(S) services are routed by hostname on the proxy cluster, so a fixed external port does not apply.","triggerScenarios":"`netbird expose --protocol http --with-external-port 8081 8080`; a script template built for tcp reuse that always passes --with-external-port.","commonSituations":"Wanting a stable public port number in an HTTP URL; leftover flag from a previous tcp/tls command in a wrapper script.","solutions":["Remove --with-external-port when using http/https; the cluster assigns the URL","To pin a public port, use an L4 protocol: `netbird expose --protocol tcp --with-external-port 5433 5432`"],"exampleFix":"# before\nnetbird expose --protocol http --with-external-port 8081 8080\n\n# after\nnetbird expose 8080","handlingStrategy":"validation","validationCode":"cluster := map[string]bool{\"tcp\": true, \"udp\": true, \"tls\": true}\nif externalPortChanged && !cluster[strings.ToLower(proto)] {\n\tlog.Fatal(\"--with-external-port is only valid with tcp/udp/tls; http/https are routed by hostname\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Only add --with-external-port when the protocol is tcp, udp, or tls","In wrappers, build the flag list conditionally per protocol instead of reusing one template","HTTP(S) exposures get their URL from the cluster; a fixed port is not a thing there"],"tags":["cli","validation","flag-combination","port","netbird-cli"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}