netbirdio/netbird · error
path_rewrite is not supported for L4 services
Error message
path_rewrite is not supported for L4 services
What it means
Returned by validateL4Target when target.options.path_rewrite is non-empty. Path rewriting edits the HTTP request path before proxying; an L4 service never parses the byte stream, so there is no path to rewrite. It is one of a family of HTTP-only options (path, custom_headers, skip_tls_verify) that validateL4Target rejects so misconfigured HTTP configs fail at API time instead of silently misbehaving.
Source
Thrown at management/internals/modules/reverseproxy/service/service.go:1069
// 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"
ModeTLS = "tls"
)
// Target protocol constants (URL scheme for backend connections).
const (
TargetProtoHTTP = "http"View on GitHub (pinned to 93e97f4bf1)
Solutions
- Remove path_rewrite (set it to empty) from the L4 target's options.
- Keep the rewrite only on http-mode targets where it is honored.
- Split shared templates so mode-inapplicable option keys are not emitted for tcp/udp/tls.
Example fix
// before
"options": { "path_rewrite": "strip-prefix" }
// after
"options": {} Defensive patterns
Strategy: validation
Validate before calling
func checkL4NoPathRewrite(o TargetOptions) error {
if o.PathRewrite != "" {
return errors.New("path_rewrite is http-only; remove it from L4 targets")
}
return nil
} Type guard
func isL4PathRewriteClean(o TargetOptions) bool {
return o.PathRewrite == ""
} Try / catch
if err := svc.Validate(); err != nil {
if strings.Contains(err.Error(), "path_rewrite is not supported for L4") {
return respondBadRequest(errors.New("clear path_rewrite on L4 targets"))
}
return respondBadRequest(err)
} Prevention
- Keep an explicit list of HTTP-only options and exclude them from L4 payload generation.
- When converting an http service to L4, rebuild options from scratch rather than editing.
- Assert the options block for L4 targets is empty (or timeout-only) in config tests.
When it happens
Trigger: An L4 target carrying "path_rewrite": "strip-prefix" (or any non-empty mode value) inherited from an HTTP service definition; shared option blocks templated across services of different modes.
Common situations: Converting an HTTP service that stripped an /api prefix into a tcp forward and leaving the rewrite rule. Configuration modules that always emit a path_rewrite key.
Related errors
- skip_tls_verify is not supported for L4 services
- custom_headers is not supported 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
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/2e95f292f09ce4c8.
Report an issue: GitHub.