{"record":{"id":"d38608c6da0ad12c","repo":"puppetlabs/puppet","slug":"short-option-name-value0-is-already-taken-plea","errorCode":null,"errorMessage":"short option name %{value0} is already taken; please specify a (different) :short","messagePattern":"short option name %(.+?) is already taken; please specify a \\(different\\) :short","errorType":"exception","errorClass":"ArgumentError","httpStatus":null,"severity":"error","filePath":"lib/puppet/util/command_line/trollop.rb","lineNumber":243,"sourceCode":"        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?\n\n      ## autobox :default for :multi (multi-occurrence) arguments\n      opts[:default] = [opts[:default]] if opts[:default] && opts[:multi] && !opts[:default].is_a?(Array)\n\n      ## fill in :multi\n      opts[:multi] ||= false\n\n      opts[:desc] ||= desc\n      @long[opts[:long]] = name\n      @short[opts[:short]] = name if opts[:short] && opts[:short] != :none\n      @specs[name] = opts\n      @order << [:opt, name]\n    end","sourceCodeStart":225,"sourceCodeEnd":261,"githubUrl":"https://github.com/puppetlabs/puppet/blob/e227c27540975c25aa22d533a52424a9d2fc886a/lib/puppet/util/command_line/trollop.rb#L225-L261","documentation":"The parser keeps an @short registry mapping single characters to option symbols. Once :short is normalized to a character, opt raises ArgumentError at trollop.rb:243 if that character is already claimed by another option. Matching is exact per character, so 'v' and 'V' are distinct and can coexist. PuppetOptionParser registers its options without :short, so inside the puppet executable this only fires on explicit duplicate declarations.","triggerScenarios":"Two options both declared with `short: 'v'`; reopening a face/application whose option already claimed the letter; a shared option module declaring the same letter in two parsers built from the same spec list.","commonSituations":"Monkey-patching an existing CLI whose letter is taken; copy-pasting option declarations between faces without checking the letters already in use.","solutions":["Give the second option a different, unused letter","Set `short: :none` on one of the two options","Leave :short unset on one option so Trollop derives a free letter from its long name"],"exampleFix":"# before\nopt :verbose, 'Verbose', short: 'v'\nopt :version, 'Version', short: 'v'   # 'v' already taken -> raise\n\n# after\nopt :verbose, 'Verbose', short: 'v'\nopt :version, 'Version', short: 'V'","handlingStrategy":"validation","validationCode":"# Track claimed short characters and check before declaring\nclaimed = {}   # char => option name\nchar = opts[:short].to_s.sub(/^-/, '')\nif claimed.key?(char)\n  raise ArgumentError, \"short '-#{char}' already used by #{claimed[char]}\"\nend\nclaimed[char] = name unless char.empty? || opts[:short] == :none","typeGuard":null,"tryCatchPattern":"begin\n  parser.opt name, desc, short: candidate\nrescue ArgumentError => e\n  raise unless e.message.include?('short option name') && e.message.include?('already taken')\n  parser.opt name, desc, short: :none\nend","preventionTips":["Keep a single registry/table of short letters per CLI and review it in code review","Leave :short unset when unsure - Trollop can derive a free letter from the long name","Test parser construction after monkey-patching a face so letter collisions surface early"],"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"}