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
- 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
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
- 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
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
- short option name %{value0} is already taken; please specify
- option '%{arg}' specified multiple times
- unsupported argument type '%{value0}'
- :type specification and default type don't match (default ty
- invalid long option name %{name}
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/81ede4e9e69c838b.
Report an issue: GitHub.