fatedier/frp · error
VirtualNet feature is not enabled; enable it by setting the
Error message
VirtualNet feature is not enabled; enable it by setting the appropriate feature gate flag
What it means
frp's client config validator rejects a configuration that sets virtualNet.address but does not enable the VirtualNet feature gate. Feature gates are an opt-in mechanism for experimental features, so the virtual network configuration is only honored when the gate 'VirtualNet' is explicitly set. The check runs during ValidateClientCommonConfig before the client starts.
Source
Thrown at pkg/config/v1/validation/client.go:61
}
for _, validator := range validators {
w, err := validator()
warnings = AppendError(warnings, w)
errs = AppendError(errs, err)
}
return warnings, errs
}
func validateFeatureGates(c *v1.ClientCommonConfig) (Warning, error) {
gates := featuregate.NewFeatureGate()
if err := gates.SetFromMap(c.FeatureGates); err != nil {
return nil, err
}
if c.VirtualNet.Address != "" {
if !gates.Enabled(featuregate.VirtualNet) {
return nil, fmt.Errorf("VirtualNet feature is not enabled; enable it by setting the appropriate feature gate flag")
}
}
return nil, nil
}
// ClientConfigRequirements describes runtime capabilities needed by a client configuration.
type ClientConfigRequirements struct {
VirtualNet bool
}
// GetClientConfigRequirements returns the runtime capabilities needed by a client configuration.
func GetClientConfigRequirements(
common *v1.ClientCommonConfig,
proxyCfgs []v1.ProxyConfigurer,
visitorCfgs []v1.VisitorConfigurer,
) ClientConfigRequirements {
requirements := ClientConfigRequirements{}
if common != nil && common.VirtualNet.Address != "" {View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Add featureGates = { VirtualNet = true } (TOML: [featureGates]\nVirtualNet = true) to the client config
- Verify the gate key casing matches featuregate.VirtualNet exactly (case-sensitive)
- If you do not need the virtual network, remove the [virtualNet] section (address field) from the config
- Check frp release notes: VirtualNet is experimental and may require a build/version that includes it
Example fix
# before [featureGates] # (missing) [virtualNet] address = "10.26.0.1/16" # after [featureGates] VirtualNet = true [virtualNet] address = "10.26.0.1/16"
Defensive patterns
Strategy: validation
Validate before calling
// Before starting frpc, validate the pair in Go:
func hasVirtualNetGate(c *v1.ClientCommonConfig) bool {
gates := featuregate.NewFeatureGate()
if err := gates.SetFromMap(c.FeatureGates); err != nil {
return false
}
return gates.Enabled(featuregate.VirtualNet) || c.VirtualNet.Address == ""
} Try / catch
if _, err := validation.ValidateClientCommonConfig(cfg); err != nil {
if strings.Contains(err.Error(), "VirtualNet feature is not enabled") {
// set FeatureGates["VirtualNet"]=true or clear VirtualNet.Address, then retry validation
}
return err
} Prevention
- Keep featureGates and the feature sections adjacent in config templates
- Add a CI step running `frpc verify -c` on every config change
- Document gate names case-sensitively
When it happens
Trigger: ClientCommonConfig has FeatureGates = nil or lacks key "VirtualNet", while c.VirtualNet.Address is non-empty. Happens when loading a TOML/YAML/JSON client config with a [virtualNet] section but no [featureGates] VirtualNet = true entry, or when gates.SetFromMap fails to see the key.
Common situations: Copying a virtualNet config block from docs or another machine without the featureGates block; upgrading frp where VirtualNet moved behind a gate; typos in the gate key (e.g. 'virtualnet' lowercase) so the gate map parses but never matches featuregate.VirtualNet.
Related errors
- exec configuration is required when type is 'exec'
- file path cannot be empty
- exec command cannot be empty
- exec env name cannot be empty
- exec env name cannot contain '='
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/529391ad9d12615a.
Report an issue: GitHub.