{"record":{"id":"5b75aebcc5f21f0f","repo":"fatedier/frp","slug":"unrecognized-feature-gate-s","errorCode":null,"errorMessage":"unrecognized feature gate: %s","messagePattern":"unrecognized feature gate: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/policy/featuregate/feature_gate.go","lineNumber":118,"sourceCode":"\tf.enabled.Store(map[Feature]bool{})\n\treturn f\n}\n\n// SetFromMap sets feature gate values from a map[string]bool\nfunc (f *featureGate) SetFromMap(m map[string]bool) error {\n\tf.lock.Lock()\n\tdefer f.lock.Unlock()\n\n\t// Copy existing state\n\tknown := maps.Clone(f.known.Load().(map[Feature]FeatureSpec))\n\tenabled := maps.Clone(f.enabled.Load().(map[Feature]bool))\n\n\t// Apply the new settings\n\tfor k, v := range m {\n\t\tk := Feature(k)\n\t\tfeatureSpec, ok := known[k]\n\t\tif !ok {\n\t\t\treturn fmt.Errorf(\"unrecognized feature gate: %s\", k)\n\t\t}\n\t\tif featureSpec.LockToDefault && featureSpec.Default != v {\n\t\t\treturn fmt.Errorf(\"cannot set feature gate %v to %v, feature is locked to %v\", k, v, featureSpec.Default)\n\t\t}\n\t\tenabled[k] = v\n\t}\n\n\t// Persist the changes\n\tf.known.Store(known)\n\tf.enabled.Store(enabled)\n\treturn nil\n}\n\n// Add adds features to the feature gate\nfunc (f *featureGate) Add(features map[Feature]FeatureSpec) error {\n\tf.lock.Lock()\n\tdefer f.lock.Unlock()\n","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/policy/featuregate/feature_gate.go#L100-L136","documentation":"featureGate.SetValues (via Set) was given a feature name that was never registered with Add. The gate keeps a known-features map; setting any key outside it fails atomically before state is persisted. This mirrors Kubernetes feature-gate semantics and protects against silently ignoring typos.","triggerScenarios":"Calling Set(map[string]bool{\"SomeFeature\": true}) where \"SomeFeature\" is not in f.known — typo, feature removed in this version, or gate not yet populated via Add.","commonSituations":"Carrying old feature-flag config into a frp version that renamed/removed a gate; typo in the featureGates config string; setting a gate before the owning package registered it.","solutions":["List valid gates via the gate's String()/known map to find the exact accepted names","Correct the typo or drop the removed gate from your configuration","If the gate should exist, ensure Add() ran before SetValues (initialization order)"],"exampleFix":"// before\nfg.Set(map[string]bool{\n  \"SupportXTCPCQuic\": true, // never registered\n})\n\n// after (use a gate actually registered by Add)\nfg.Set(map[string]bool{\n  \"SomeRegisteredGate\": true,\n})","handlingStrategy":"validation","validationCode":"// Check gate existence before setting\nall, _ := fg.KnownFeatures() // or export the known map\nfor k := range requested {\n    if _, ok := all[k]; !ok {\n        return fmt.Errorf(\"unknown feature gate %q; available: %v\", k, all)\n    }\n}\nreturn fg.Set(requested)","typeGuard":null,"tryCatchPattern":"if err := fg.Set(requested); err != nil && strings.Contains(err.Error(), \"unrecognized feature gate\") {\n    // fail fast on typos; do not silently ignore\n    return err\n}","preventionTips":["Fail startup on unrecognized gates rather than skipping them — they are almost always typos","Keep feature-gate config in version control and review it on every frp upgrade"],"tags":["feature-flags","configuration","go"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}