fatedier/frp · error
cannot add feature gates after the feature gate is closed
Error message
cannot add feature gates after the feature gate is closed
What it means
Add() was called on a feature gate after Close() sealed it. Closing a gate freezes the known-feature set so later code cannot mutate feature availability; any Add after that is a programming error caught here.
Source
Thrown at pkg/policy/featuregate/feature_gate.go:138
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")
}
// Copy existing state
known := maps.Clone(f.known.Load().(map[Feature]FeatureSpec))
// Add new features
for name, spec := range features {
if existingSpec, found := known[name]; found {
if existingSpec == spec {
continue
}
return fmt.Errorf("feature gate %q with different spec already exists: %v", name, existingSpec)
}
known[name] = spec
}
// Persist changes
f.known.Store(known)View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Move all Add calls before Close() in the startup sequence
- Register features in init() or an explicit registration phase, then Close the gate once
- If late registration is legitimate, keep the gate open (do not Close) — but prefer fixing the order
Example fix
// before
fg.Close()
fg.Add(map[Feature]FeatureSpec{"Late": {}}) // error
// after
fg.Add(map[Feature]FeatureSpec{"Late": {}})
fg.Close() Defensive patterns
Strategy: validation
Validate before calling
if fg.Closed() {
return errors.New("gate closed; register features earlier in startup")
} Try / catch
if err := fg.Add(specs); err != nil && strings.Contains(err.Error(), "after the feature gate is closed") {
return fmt.Errorf("init-order bug: %w", err)
} Prevention
- Register all feature gates in init()/early startup; call Close exactly once, last
- Add a startup assertion that gates are closed only after all modules register
When it happens
Trigger: Calling featureGate.Add(features) after featureGate.Close() — typically late registration from an init path or a lazily-loaded module running after the gate was closed at startup.
Common situations: Plugin or module registering its feature gates in init() while main closes the gate before all imports finish; code refactor moved Add after the Close call.
Related errors
- send CloseProxy request to plugin errors: %s
- unrecognized feature gate: %s
- cannot set feature gate %v to %v, feature is locked to %v
- feature gate %q with different spec already exists: %v
- control manager is closed
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/69d6f38199b12d39.
Report an issue: GitHub.