{"record":{"id":"d33d9882d2069cb0","repo":"etcd-io/etcd","slug":"feature-q-is-not-registered-in-featuregate-q","errorCode":null,"errorMessage":"feature %q is not registered in FeatureGate %q","messagePattern":"feature %q is not registered in FeatureGate %q","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/featuregate/feature_gate.go","lineNumber":342,"sourceCode":"}\n\n// GetAll returns a copy of the map of known feature names to feature specs.\nfunc (f *featureGate) GetAll() map[Feature]FeatureSpec {\n\tretval := map[Feature]FeatureSpec{}\n\tmaps.Copy(retval, f.known.Load().(map[Feature]FeatureSpec))\n\treturn retval\n}\n\n// Enabled returns true if the key is enabled.  If the key is not known, this call will panic.\nfunc (f *featureGate) Enabled(key Feature) bool {\n\tif v, ok := f.enabled.Load().(map[Feature]bool)[key]; ok {\n\t\treturn v\n\t}\n\tif v, ok := f.known.Load().(map[Feature]FeatureSpec)[key]; ok {\n\t\treturn v.Default\n\t}\n\n\tpanic(fmt.Errorf(\"feature %q is not registered in FeatureGate %q\", key, f.featureGateName))\n}\n\n// AddFlag adds a flag for setting global feature gates to the specified FlagSet.\nfunc (f *featureGate) AddFlag(fs *flag.FlagSet, flagName string) {\n\tif flagName == \"\" {\n\t\tflagName = defaultFlagName\n\t}\n\tf.lock.Lock()\n\t// TODO(mtaufen): Shouldn't we just close it on the first Set/SetFromMap instead?\n\t// Not all components expose a feature gates flag using this AddFlag method, and\n\t// in the future, all components will completely stop exposing a feature gates flag,\n\t// in favor of componentconfig.\n\tf.closed = true\n\tf.lock.Unlock()\n\n\tknown := f.KnownFeatures()\n\tfs.Var(f, flagName, \"\"+\n\t\t\"A set of key=value pairs that describe feature gates for alpha/experimental features. \"+","sourceCodeStart":324,"sourceCodeEnd":360,"githubUrl":"https://github.com/etcd-io/etcd/blob/f744d457f484e9f748a0700b48ef96dcf792df33/pkg/featuregate/feature_gate.go#L324-L360","documentation":"This panic is thrown by featuregate's Enabled() when the requested Feature key is present in neither the runtime 'enabled' map nor the registered 'known' specs map of that FeatureGate instance. It is an intentional fail-fast: silently returning false for an unknown gate would hide configuration mistakes. The gate's specs are populated via Add/AddMap/SetFromMap before Enabled is consulted, so an unknown key means the caller and the registration code disagree.","triggerScenarios":"Calling featureGate.Enabled(key) where key was never registered with featureGate.Add(...) or AddMap(...). Typical in etcd's embed server path: cfg.AddFeatureGate / options parsing register gates first, then component code calls Enabled(\"SomeFeature\"); if the component references a feature constant introduced (or renamed) in a different version than the one that registered the gates, the panic fires.","commonSituations":"Version skew between etcd modules (e.g. server registered gates at v3.5 while shared code expects a v3.6 gate name); typos when passing a feature as a raw string from flags/env; calling Enabled on a freshly created gate (featuregate.New) before any Add; copy-pasting a feature name that was removed (graduated/removed features disappear from known maps after cleanup).","solutions":["Find where the FeatureGate is populated (embed/config.go or wherever Add/AddMap/SetFromMap is called) and add the missing feature with featuregate.Add(FeatureName, FeatureSpec{Default: false, PreRelease: ...}) before any Enabled call.","If the feature exists upstream, align module versions (go.mod / go.work) so the registering code and the Enabled caller come from the same etcd release; renamed/graduated gates must be referenced by their current constant.","List what the gate actually knows with f.KnownFeatures() (or inspect the AddMap literal) to confirm the exact spelling of the key.","If you only want an optional check, test membership of KnownFeatures() output instead of calling Enabled for possibly-absent keys."],"exampleFix":"// before\nfg := featuregate.New(\"my-gate\")\n// ... component later calls:\nif fg.Enabled(featuregate.Feature(\"MyFeature\")) { ... } // panics: never registered\n\n// after\nfg := featuregate.New(\"my-gate\")\nerr := fg.Add(map[featuregate.Feature]featuregate.FeatureSpec{\n\t\"MyFeature\": {Default: false, PreRelease: featuregate.Alpha},\n})\nif err != nil {\n\treturn err\n}\n// now Enabled(\"MyFeature\") returns the default instead of panicking","handlingStrategy":"validation","validationCode":"// Before calling Enabled, confirm the feature is registered:\nfunc featureRegistered(fg featuregate.FeatureGate, key featuregate.Feature) bool {\n\tfor _, k := range fg.KnownFeatures() { // KnownFeatures includes lock/alpha markers; check raw membership instead\n\t\tif strings.TrimPrefix(k, \"lock_\") == string(key) || k == string(key) {\n\t\t\treturn true\n\t\t}\n\t}\n\treturn false\n}\n\nif !featureRegistered(fg, \"MyFeature\") {\n\t// register it or skip the check\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Register all features (Add/AddMap) in one place during gate construction, before any goroutine can call Enabled.","Reference features via typed constants, not raw strings, so renames surface as compile errors.","Keep all etcd modules on the same release version to avoid gate-name skew.","In tests, construct the gate through the same helper production code uses so the spec map is always populated."],"tags":["featuregate","configuration","panic","version-skew"],"backgroundTag":null,"analyzedSha":"f744d457f484e9f748a0700b48ef96dcf792df33","analyzedAt":"2026-08-15T09:39:50.079Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}