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

  1. Remove path_rewrite (set it to empty) from the L4 target's options.
  2. Keep the rewrite only on http-mode targets where it is honored.
  3. 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

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


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/2e95f292f09ce4c8. Report an issue: GitHub.