puppetlabs/puppet · error · ArgumentError

long option name %{value0} is already taken; please specify

Error message

long option name %{value0} is already taken; please specify a (different) :long

What it means

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.

Source

Thrown at lib/puppet/util/command_line/trollop.rb:230

          raise ArgumentError, _("unsupported argument type '%{value0}'") % { value0: opts[:default].class.name }
        end

      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

      opts[:type] = opts[:type] || type_from_default || :flag

      ## fill in :long
      opts[:long] = opts[:long] ? opts[:long].to_s : name.to_s.tr("_", "-")
      opts[:long] =
        case opts[:long]
        when /^--([^-].*)$/
          ::Regexp.last_match(1)
        when /^[^-]/
          opts[:long]
        else
          raise ArgumentError, _("invalid long option name %{name}") % { name: opts[:long].inspect }
        end
      raise ArgumentError, _("long option name %{value0} is already taken; please specify a (different) :long") % { value0: opts[:long].inspect } if @long[opts[:long]]

      ## fill in :short
      unless opts[:short] == :none
        opts[:short] = opts[:short].to_s if opts[:short]
      end
      opts[:short] = case opts[:short]
                     when /^-(.)$/; ::Regexp.last_match(1)
                     when nil, :none, /^.$/; opts[:short]
                     else raise ArgumentError, _("invalid short option name '%{name}'") % { name: opts[:short].inspect }
                     end

      if opts[:short]
        raise ArgumentError, _("short option name %{value0} is already taken; please specify a (different) :short") % { value0: opts[:short].inspect } if @short[opts[:short]]
        raise ArgumentError, _("a short option name can't be a number or a dash") if opts[:short] =~ INVALID_SHORT_ARG_REGEX
      end

      ## fill in :default for flags
      opts[:default] = false if opts[:type] == :flag && opts[:default].nil?

View on GitHub (pinned to e227c27540)

Solutions

  1. Rename one of the colliding options (its symbol or :long) so every long name is unique
  2. Delete the duplicate declaration and keep a single canonical option
  3. When overriding the behavior of an existing option, reuse the same symbol instead of registering a second one

Example fix

# before
opt :dry_run, 'Do a dry run'
opt :'dry-run', 'Alias for dry run'   # both map to '--dry-run' -> raise

# after
opt :dry_run, 'Do a dry run'          # only '--dry-run'
Defensive patterns

Strategy: validation

Validate before calling

# Before declaring, compute the long name the way Trollop does and check uniqueness
normalized = ->(name, long = nil) { (long || name.to_s).to_s.sub(/^--/, '').tr('_', '-') }

taken = Set.new
long = normalized.call(name, opts[:long])
if taken.include?(long)
  raise ArgumentError, "long option '--#{long}' already declared"
end
taken << long

Try / catch

begin
  parser.opt name, desc, opts
rescue ArgumentError => e
  raise unless e.message.include?('already taken')
  opts = opts.merge(long: "#{opts[:long] || name}-2")  # disambiguate deliberately
  retry
end

Prevention

When it happens

Trigger: `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.

Common situations: 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.

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/81ede4e9e69c838b. Report an issue: GitHub.