{"record":{"id":"87601bc8d9381fe2","repo":"flippercloud/flipper","slug":"group-name-inspect-has-already-been-registered","errorCode":null,"errorMessage":"Group #{name.inspect} has already been registered","messagePattern":"Group #(.+?) has already been registered","errorType":"exception","errorClass":"Flipper::DuplicateGroup","httpStatus":null,"severity":"error","filePath":"lib/flipper.rb","lineNumber":138,"sourceCode":"  #\n  # name - The Symbol name of the group.\n  # block - The block that should be used to determine if the group matches a\n  #         given actor.\n  #\n  # Examples\n  #\n  #   Flipper.register(:admins) { |actor|\n  #     actor.respond_to?(:admin?) && actor.admin?\n  #   }\n  #\n  # Returns a Flipper::Group.\n  # Raises Flipper::DuplicateGroup if the group is already registered.\n  def register(name, &block)\n    group = Types::Group.new(name, &block)\n    groups_registry.add(group.name, group)\n    group\n  rescue Registry::DuplicateKey\n    raise DuplicateGroup, \"Group #{name.inspect} has already been registered\"\n  end\n\n  # Public: Returns a Set of registered Types::Group instances.\n  def groups\n    groups_registry.values.to_set\n  end\n\n  # Public: Returns a Set of symbols where each symbol is a registered\n  # group name. If you just want the names, this is more efficient than doing\n  # `Flipper.groups.map(&:name)`.\n  def group_names\n    groups_registry.keys.to_set\n  end\n\n  # Public: Clears the group registry.\n  #\n  # Returns nothing.\n  def unregister_groups","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/flippercloud/flipper/blob/1f86de3ec91521585b156445e156642938b19cb0/lib/flipper.rb#L120-L156","documentation":"Flipper keeps a process-global registry of groups (Flipper.groups_registry). Flipper.register(name, &block) inserts the group into that registry, and a second registration of the same name raises Flipper::DuplicateGroup instead of silently replacing the first block. This guards against two different match blocks both claiming one group name, which would make actor matching ambiguous. The registry only resets via Flipper.unregister_groups or process restart.","triggerScenarios":"Calling Flipper.register(:admins) { ... } twice with the same Symbol in one process; calling Flipper.setup/initialization code that registers groups more than once; registering groups in a file that gets loaded twice (require + Zeitwerk autoload, or initializer re-run by Spring/rake tasks that reload initializers).","commonSituations":"Rails development reloading: groups registered in app/ code that Zeitwerk reloads, or in config.to_prepare blocks that fire on every code reload; registering the same group in both an initializer and a monkey patch/decorator; RSpec suites that call Flipper.register in a helper without unregistering between examples; engines/gems that each register the same group name.","solutions":["Register each group only once, and place registration in config/initializers/flipper.rb (runs once per process) rather than reloadable app code.","If registration may run repeatedly (to_prepare, tests), guard it: Flipper.register(:admins) { ... } unless Flipper.group_exists?(:admins).","In test suites, add Flipper.unregister_groups to a before/after hook so each example starts clean.","If you genuinely must redefine a group at runtime, call Flipper.unregister_groups first, then re-register everything."],"exampleFix":"// before (app/flipper_groups.rb — Zeitwerk reloads this in dev, second load raises)\nFlipper.register(:admins) { |actor| actor.respond_to?(:admin?) && actor.admin? }\n\n# after (config/initializers/flipper.rb — idempotent, runs once per process)\nRails.application.config.to_prepare do\n  Flipper.register(:admins) { |actor| actor.respond_to?(:admin?) && actor.admin? } unless Flipper.group_exists?(:admins)\nend","handlingStrategy":"validation","validationCode":"Flipper.register(:admins) { |actor| actor.admin? } unless Flipper.group_exists?(:admins)","typeGuard":null,"tryCatchPattern":"begin\n  Flipper.register(:admins, &block)\nrescue Flipper::DuplicateGroup\n  # existing registration is authoritative; only safe if the block is identical\n  raise if ENV[\"RAILS_ENV\"] == \"production\"\nend","preventionTips":["Register groups in config/initializers (runs once per process), never in reloadable app code.","Make registration idempotent with Flipper.group_exists?(name) guards.","Call Flipper.unregister_groups in test before/after hooks.","Centralize all Flipper.register calls in one file so duplicates are obvious in review."],"tags":["ruby","flipper","groups","duplicate-registration","rails-reloading"],"backgroundTag":"duplicate-registration","analyzedSha":"1f86de3ec91521585b156445e156642938b19cb0","analyzedAt":"2026-08-23T04:36:09.896Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}