fatedier/frp · error
cannot set feature gate %v to %v, feature is locked to %v
Error message
cannot set feature gate %v to %v, feature is locked to %v
What it means
An attempt to change a feature gate away from its default value, but the gate's FeatureSpec has LockToDefault: true. Locked gates are stage-locked (alpha/beta gates that must not be toggled in production); SetValues refuses and reports the locked default.
Source
Thrown at pkg/policy/featuregate/feature_gate.go:121
// SetFromMap sets feature gate values from a map[string]bool
func (f *featureGate) SetFromMap(m map[string]bool) error {
f.lock.Lock()
defer f.lock.Unlock()
// Copy existing state
known := maps.Clone(f.known.Load().(map[Feature]FeatureSpec))
enabled := maps.Clone(f.enabled.Load().(map[Feature]bool))
// Apply the new settings
for k, v := range m {
k := Feature(k)
featureSpec, ok := known[k]
if !ok {
return fmt.Errorf("unrecognized feature gate: %s", k)
}
if featureSpec.LockToDefault && featureSpec.Default != v {
return fmt.Errorf("cannot set feature gate %v to %v, feature is locked to %v", k, v, featureSpec.Default)
}
enabled[k] = v
}
// Persist the changes
f.known.Store(known)
f.enabled.Store(enabled)
return nil
}
// Add adds features to the feature gate
func (f *featureGate) Add(features map[Feature]FeatureSpec) error {
f.lock.Lock()
defer f.lock.Unlock()
if f.closed {
return fmt.Errorf("cannot add feature gates after the feature gate is closed")
}View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Remove that gate from your Set/config — it cannot be changed by design
- Check the feature's FeatureSpec: the locked default is the only legal value
- If you truly need the other value, use a frp build/version where the gate is not locked
Example fix
// before
fg.Set(map[string]bool{"LockedGate": false}) // error: locked to true
// after — omit locked gates entirely
fg.Set(map[string]bool{"UnlockedGate": true}) Defensive patterns
Strategy: validation
Validate before calling
// Skip locked gates before calling Set
specs, _ := fg.KnownFeatures()
settable := map[string]bool{}
for k, v := range requested {
if s, ok := specs[k]; ok && !s.LockToDefault {
settable[k] = v
}
}
return fg.Set(settable) Try / catch
if err := fg.Set(requested); err != nil && strings.Contains(err.Error(), "locked to") {
log.Warn("ignoring locked feature gate:", err)
} Prevention
- Never put locked (LockToDefault) gates in user config files
- Drop stale gate entries from config when upgrading frp versions
When it happens
Trigger: Calling Set with a value different from featureSpec.Default for a feature whose spec declares LockToDefault — e.g. trying to enable/disable a locked alpha gate from config.
Common situations: Trying to turn off a GA-locked gate or turn on a locked deprecated gate via the featureGates config key; config copied from docs/examples that toggle gates the current version locks.
Related errors
- unrecognized feature gate: %s
- feature gate %q with different spec already exists: %v
- ErrHealthCheckType
- unit not support
- type is required
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/d3394afbd786dc66.
Report an issue: GitHub.