{"record":{"id":"81ede4e9e69c838b","repo":"puppetlabs/puppet","slug":"long-option-name-value0-is-already-taken-pleas","errorCode":null,"errorMessage":"long option name %{value0} is already taken; please specify a (different) :long","messagePattern":"long option name %(.+?) is already taken; please specify a \\(different\\) :long","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/util/command_line/trollop.rb","lineNumber":230,"sourceCode":"          raise ArgumentError, _(\"unsupported argument type '%{value0}'\") % { value0: opts[:default].class.name }\n        end\n\n      raise ArgumentError, _(\":type specification and default type don't match (default type is %{type_from_default})\") % { type_from_default: type_from_default } if opts[:type] && type_from_default && opts[:type] != type_from_default\n\n      opts[:type] = opts[:type] || type_from_default || :flag\n\n      ## fill in :long\n      opts[:long] = opts[:long] ? opts[:long].to_s : name.to_s.tr(\"_\", \"-\")\n      opts[:long] =\n        case opts[:long]\n        when /^--([^-].*)$/\n          ::Regexp.last_match(1)\n        when /^[^-]/\n          opts[:long]\n        else\n          raise ArgumentError, _(\"invalid long option name %{name}\") % { name: opts[:long].inspect }\n        end\n      raise ArgumentError, _(\"long option name %{value0} is already taken; please specify a (different) :long\") % { value0: opts[:long].inspect } if @long[opts[:long]]\n\n      ## fill in :short\n      unless opts[:short] == :none\n        opts[:short] = opts[:short].to_s if opts[:short]\n      end\n      opts[:short] = case opts[:short]\n                     when /^-(.)$/; ::Regexp.last_match(1)\n                     when nil, :none, /^.$/; opts[:short]\n                     else raise ArgumentError, _(\"invalid short option name '%{name}'\") % { name: opts[:short].inspect }\n                     end\n\n      if opts[:short]\n        raise ArgumentError, _(\"short option name %{value0} is already taken; please specify a (different) :short\") % { value0: opts[:short].inspect } if @short[opts[:short]]\n        raise ArgumentError, _(\"a short option name can't be a number or a dash\") if opts[:short] =~ INVALID_SHORT_ARG_REGEX\n      end\n\n      ## fill in :default for flags\n      opts[:default] = false if opts[:type] == :flag && opts[:default].nil?","sourceCodeStart":212,"sourceCodeEnd":248,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/command_line/trollop.rb#L212-L248","documentation":"The parser keeps an @long registry mapping long names to option symbols. After validating the long name's shape, opt raises ArgumentError at trollop.rb:230 if that name was already registered by a previous opt call. Collisions occur with an explicitly duplicated :long and, less obviously, when two different symbols normalize to the same long name because underscores are converted to dashes.","triggerScenarios":"`opt :dry_run` followed by `opt :'dry-run'` — both normalize to 'dry-run'; two options both declaring `long: 'verbose'`; re-declaring an option after reopening a face/application on a Parser instance that already has it.","commonSituations":"Monkey-patching or reopening a Puppet face that already declared the option; mixing :some_option and :'some-option' spellings across files; copy-pasted option blocks between faces.","solutions":["Rename one of the colliding options (its symbol or :long) so every long name is unique","Delete the duplicate declaration and keep a single canonical option","When overriding the behavior of an existing option, reuse the same symbol instead of registering a second one"],"exampleFix":"# before\nopt :dry_run, 'Do a dry run'\nopt :'dry-run', 'Alias for dry run'   # both map to '--dry-run' -> raise\n\n# after\nopt :dry_run, 'Do a dry run'          # only '--dry-run'","handlingStrategy":"validation","validationCode":"# Before declaring, compute the long name the way Trollop does and check uniqueness\nnormalized = ->(name, long = nil) { (long || name.to_s).to_s.sub(/^--/, '').tr('_', '-') }\n\ntaken = Set.new\nlong = normalized.call(name, opts[:long])\nif taken.include?(long)\n  raise ArgumentError, \"long option '--#{long}' already declared\"\nend\ntaken << long","typeGuard":null,"tryCatchPattern":"begin\n  parser.opt name, desc, opts\nrescue ArgumentError => e\n  raise unless e.message.include?('already taken')\n  opts = opts.merge(long: \"#{opts[:long] || name}-2\")  # disambiguate deliberately\n  retry\nend","preventionTips":["Standardize on one spelling per option (prefer underscore-free symbols) across the codebase","When reopening a face or application, check which options already exist before declaring","Assert the full option list in a spec so accidental duplicate long names fail in CI, not at runtime"],"tags":["puppet","trollop","cli","option-parsing","duplicate"],"backgroundTag":"duplicate-option-name","analyzedSha":"e227c27540975c25aa22d533a52424a9d2fc886a","analyzedAt":"2026-08-21T20:49:46.650Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}