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

  1. Move all Add calls before Close() in the startup sequence
  2. Register features in init() or an explicit registration phase, then Close the gate once
  3. 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

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


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/69d6f38199b12d39. Report an issue: GitHub.