netbirdio/netbird · error
request_timeout must be positive for L4 services
Error message
request_timeout must be positive for L4 services
What it means
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.
Source
Thrown at management/internals/modules/reverseproxy/service/service.go:1063
}
case TargetTypeSubnet:
if target.Host == "" {
return errors.New("target host is required for subnet targets")
}
case TargetTypeCluster:
// target_id carries the cluster address; the proxy resolves
// the upstream at request time.
default:
return fmt.Errorf("invalid target_type %q for L4 service", target.TargetType)
}
if target.Path != nil && *target.Path != "" && *target.Path != "/" {
return errors.New("path is not supported for L4 services")
}
if target.Options.SessionIdleTimeout < 0 {
return errors.New("session_idle_timeout must be positive for L4 services")
}
if target.Options.RequestTimeout < 0 {
return errors.New("request_timeout must be positive for L4 services")
}
if target.Options.SkipTLSVerify {
return errors.New("skip_tls_verify is not supported for L4 services")
}
if target.Options.PathRewrite != "" {
return errors.New("path_rewrite is not supported for L4 services")
}
if len(target.Options.CustomHeaders) > 0 {
return errors.New("custom_headers is not supported for L4 services")
}
return nil
}
// Service mode constants.
const (
ModeHTTP = "http"
ModeTCP = "tcp"
ModeUDP = "udp"View on GitHub (pinned to 93e97f4bf1)
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.
Example fix
// before
"options": { "request_timeout": -5000000000 }
// after
"options": { "request_timeout": 30000000000 } Defensive patterns
Strategy: validation
Validate before calling
func checkL4RequestTimeout(o TargetOptions) error {
if o.RequestTimeout < 0 {
return errors.New("request_timeout must be >= 0 (0 = default)")
}
return nil
} Type guard
func isL4RequestTimeoutValid(o TargetOptions) bool {
return o.RequestTimeout >= 0
} Try / catch
if err := svc.Validate(); err != nil {
if strings.Contains(err.Error(), "request_timeout") {
return respondBadRequest(errors.New("use 0 for default or a positive duration; negatives are invalid"))
}
return respondBadRequest(err)
} Prevention
- 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.
When it happens
Trigger: 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'.
Common situations: 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.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- session_idle_timeout must be positive for L4 services
- 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
- target_id is required for L4 services
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/cb6ec6a62218bba2.
Report an issue: GitHub.