{"record":{"id":"cb6ec6a62218bba2","repo":"netbirdio/netbird","slug":"request-timeout-must-be-positive-for-l4-services","errorCode":null,"errorMessage":"request_timeout must be positive for L4 services","messagePattern":"request_timeout must be positive for L4 services","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"management/internals/modules/reverseproxy/service/service.go","lineNumber":1063,"sourceCode":"\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}\n\n// Service mode constants.\nconst (\n\tModeHTTP = \"http\"\n\tModeTCP  = \"tcp\"\n\tModeUDP  = \"udp\"","sourceCodeStart":1045,"sourceCodeEnd":1081,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/management/internals/modules/reverseproxy/service/service.go#L1045-L1081","documentation":"Returned by validateL4Target when target.options.request_timeout is negative. As with session_idle_timeout, the message overstates the rule: only values below zero are rejected, and zero means unset/default. These L4 timeouts bound how long a session/request may run on the passthrough, so a negative value has no meaning.","triggerScenarios":"An L4 target with a negative request_timeout in the payload; a client computing request_timeout as a difference that can go negative; configs ported from tools where negative timeout means 'disabled'.","commonSituations":"Reusing -1 conventions from other proxy configs. Duration math without a lower clamp. Copy-paste between session_idle_timeout and request_timeout where one was intentionally negative for testing.","solutions":["Set request_timeout to 0 (omit) for the default, or a positive duration for an explicit bound.","Clamp computed durations in client code: if d < 0 { d = 0 }.","Keep in mind both L4 timeouts share the same rule - fix them together when cleaning a template."],"exampleFix":"// before\n\"options\": { \"request_timeout\": -5000000000 }\n\n// after\n\"options\": { \"request_timeout\": 30000000000 }","handlingStrategy":"validation","validationCode":"func checkL4RequestTimeout(o TargetOptions) error {\n\tif o.RequestTimeout < 0 {\n\t\treturn errors.New(\"request_timeout must be >= 0 (0 = default)\")\n\t}\n\treturn nil\n}","typeGuard":"func isL4RequestTimeoutValid(o TargetOptions) bool {\n\treturn o.RequestTimeout >= 0\n}","tryCatchPattern":"if err := svc.Validate(); err != nil {\n\tif strings.Contains(err.Error(), \"request_timeout\") {\n\t\treturn respondBadRequest(errors.New(\"use 0 for default or a positive duration; negatives are invalid\"))\n\t}\n\treturn respondBadRequest(err)\n}","preventionTips":["Validate both L4 timeouts together - they share the no-negatives rule.","Express durations in Go with time.Duration constants, not raw nanosecond literals.","Boundary-test your config parser with 0, positive, and negative values."],"tags":["netbird","reverse-proxy","validation","l4","timeout","configuration","go"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}