puppetlabs/puppet · error · CommandlineError
option '%{arg}' specified multiple times
Error message
option '%{arg}' specified multiple times What it means
While resolving tokens, parse records each option symbol in given_args; if the same symbol appears again and the option was not declared with :multi => true, parse raises CommandlineError at trollop.rb:369 instead of applying last-wins semantics. Multi options accumulate values; single options treat a repeat as a user error. PuppetOptionParser registers puppet's own options with :multi => true (puppet_option_parser.rb:57), so repeats of core puppet flags are allowed and the last value wins — this error mainly affects tools and faces that call the vendored Trollop directly.
Source
Thrown at lib/puppet/util/command_line/trollop.rb:369
partial_match = @long[::Regexp.last_match(1).tr('-', '_')] || @long[::Regexp.last_match(1).tr('_', '-')] || @long["[no-]#{::Regexp.last_match(1).tr('-', '_')}"] || @long["[no-]#{::Regexp.last_match(1).tr('_', '-')}"]
if partial_match
Puppet.deprecation_warning _("Partial argument match detected: correct argument is %{partial_match}, got %{arg}. Partial argument matching is deprecated and will be removed in a future release.") % { arg: arg, partial_match: partial_match }
end
partial_match
else
possible_match
end
else
raise CommandlineError, _("invalid argument syntax: '%{arg}'") % { arg: arg }
end
unless sym
next 0 if ignore_invalid_options
raise CommandlineError, _("unknown argument '%{arg}'") % { arg: arg } unless sym
end
if given_args.include?(sym) && !@specs[sym][:multi]
raise CommandlineError, _("option '%{arg}' specified multiple times") % { arg: arg }
end
given_args[sym] ||= {}
given_args[sym][:arg] = arg
given_args[sym][:params] ||= []
# The block returns the number of parameters taken.
num_params_taken = 0
unless params.nil?
if SINGLE_ARG_TYPES.include?(@specs[sym][:type])
given_args[sym][:params] << params[0, 1] # take the first parameter
num_params_taken = 1
elsif MULTI_ARG_TYPES.include?(@specs[sym][:type])
given_args[sym][:params] << params # take all the parameters
num_params_taken = params.size
endView on GitHub (pinned to e227c27540)
Solutions
- Pass the option once with the desired value
- Declare the option with `:multi => true` if repeats should be accepted (values accumulate, or last wins for single-arg types)
- De-duplicate the option in your wrapper or ARGV pre-processing before invoking the command
Example fix
# before opt :server, 'Server host', type: :string # no :multi $ mytool --server a --server b -> raise # after opt :server, 'Server host', type: :string, multi: true
Defensive patterns
Strategy: validation
Validate before calling
# De-duplicate single-shot options in argv before parsing
seen = {}
cleaned = []
value_taking = ->(t) { t =~ /^--\S+=$/ || t =~ /^--no-/ || t == '--' } # adjust to your option set
tokens = argv.dup
until tokens.empty?
t = tokens.shift
if (m = t.match(/^--([^=]+)(?:=(.*))?$/)) && !multi_options.include?(m[1].tr('-', '_').to_sym)
cleaned.reject! { |c| c =~ /^--#{m[1]}=/ } # last wins, like explicit :multi
cleaned << t
cleaned << tokens.shift if m[2].nil? && next_is_value(tokens.first) # keep its value
else
cleaned << t
end
end Try / catch
begin
opts = parser.parse(argv)
rescue Puppet::Util::CommandLine::Trollop::CommandlineError => e
raise unless e.message.include?('specified multiple times')
opts = parser.parse(argv.each_with_object({}) { |t, h| (h[t[/^--[^=]+/] || t] ||= []) << t }.values.map(&:last))
end Prevention
- Pass each single-shot option exactly once; put overrides in one place (wrapper, config, or CLI - not several)
- Declare repeatable options with multi: true when repeats are legitimate
- In wrapper scripts, check whether a flag is already present before appending it
When it happens
Trigger: `mytool --server a --server b` where :server was declared without :multi; a wrapper script appending a default flag onto a user-supplied ARGV that already contains it; an alias or config layer re-invoking the same option.
Common situations: Wrapper scripts that blindly append default flags; users overriding a value already injected by a profile or environment; combining config-file and CLI sources that map to the same option.
Related errors
- long option name %{value0} is already taken; please specify
- short option name %{value0} is already taken; please specify
- 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/338369b400adc39a.
Report an issue: GitHub.