{"record":{"id":"922a2fa51a39cb4d","repo":"netbirdio/netbird","slug":"path-is-not-supported-for-l4-services","errorCode":null,"errorMessage":"path is not supported for L4 services","messagePattern":"path is not supported for L4 services","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"management/internals/modules/reverseproxy/service/service.go","lineNumber":1057,"sourceCode":"\t\treturn errors.New(\"target port is required for L4 services\")\n\t}\n\tswitch target.TargetType {\n\tcase TargetTypePeer, TargetTypeHost, TargetTypeDomain:\n\t\tif err := validateDirectUpstreamHost(0, target); err != nil {\n\t\t\treturn err\n\t\t}\n\tcase TargetTypeSubnet:\n\t\tif target.Host == \"\" {\n\t\t\treturn errors.New(\"target host is required for subnet targets\")\n\t\t}\n\tcase TargetTypeCluster:\n\t\t// target_id carries the cluster address; the proxy resolves\n\t\t// the upstream at request time.\n\tdefault:\n\t\treturn fmt.Errorf(\"invalid target_type %q for L4 service\", target.TargetType)\n\t}\n\tif target.Path != nil && *target.Path != \"\" && *target.Path != \"/\" {\n\t\treturn errors.New(\"path is not supported for L4 services\")\n\t}\n\tif target.Options.SessionIdleTimeout < 0 {\n\t\treturn errors.New(\"session_idle_timeout must be positive for L4 services\")\n\t}\n\tif target.Options.RequestTimeout < 0 {\n\t\treturn errors.New(\"request_timeout must be positive for L4 services\")\n\t}\n\tif target.Options.SkipTLSVerify {\n\t\treturn errors.New(\"skip_tls_verify is not supported for L4 services\")\n\t}\n\tif target.Options.PathRewrite != \"\" {\n\t\treturn errors.New(\"path_rewrite is not supported for L4 services\")\n\t}\n\tif len(target.Options.CustomHeaders) > 0 {\n\t\treturn errors.New(\"custom_headers is not supported for L4 services\")\n\t}\n\treturn nil\n}","sourceCodeStart":1039,"sourceCodeEnd":1075,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/management/internals/modules/reverseproxy/service/service.go#L1039-L1075","documentation":"Returned by validateL4Target when the target's Path pointer is non-nil and set to anything other than \"\" or \"/\". Path-based routing is an HTTP concept (choosing a backend by URL path); an L4 service forwards opaque bytes and never inspects them, so a path cannot influence routing. The empty-string and \"/\" exceptions exist so HTTP-derived defaults survive the copy.","triggerScenarios":"An L4 target whose JSON carries \"path\": \"/api\" left over from an HTTP multi-target definition; YAML anchors shared between HTTP and TCP service templates that include a path key.","commonSituations":"Cloning an HTTP service (where each target had a path) into a tcp/udp/tls service. Tooling that emits a default path of \"/v1\" for every target regardless of mode.","solutions":["Remove the path key (or set it to null, \"\", or exactly \"/\") on L4 targets.","Clean shared templates so mode-specific fields are conditionally emitted.","If you were trying to route by path, that is mode http territory - restructure the service accordingly."],"exampleFix":"// before\n{ \"target_type\": \"peer\", \"target_id\": \"peer-a\", \"port\": 5432, \"path\": \"/db\" }\n\n// after\n{ \"target_type\": \"peer\", \"target_id\": \"peer-a\", \"port\": 5432 }","handlingStrategy":"validation","validationCode":"func checkL4NoPath(t Target) error {\n\tif t.Path != nil && *t.Path != \"\" && *t.Path != \"/\" {\n\t\treturn errors.New(\"path is http-only; remove it from L4 targets\")\n\t}\n\treturn nil\n}","typeGuard":"func isL4PathClean(t Target) bool {\n\treturn t.Path == nil || *t.Path == \"\" || *t.Path == \"/\"\n}","tryCatchPattern":"if err := svc.Validate(); err != nil {\n\tif strings.Contains(err.Error(), \"path is not supported for L4\") {\n\t\treturn respondBadRequest(errors.New(\"delete the path key from L4 targets\"))\n\t}\n\treturn respondBadRequest(err)\n}","preventionTips":["Strip HTTP-only keys (path, path_rewrite, custom_headers, skip_tls_verify) when generating L4 payloads.","Avoid YAML anchors shared across HTTP and L4 service templates.","Diff payloads against a known-good golden file per mode in CI."],"tags":["netbird","reverse-proxy","validation","l4","path","targets","go"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}