puppetlabs/puppet · error · ArgumentError
unsupported argument type '%{value0}'
Error message
unsupported argument type '%{value0}' What it means
Puppet vendors the Trollop option parser (lib/puppet/util/command_line/trollop.rb) behind PuppetOptionParser for the `puppet` executable and face options. When Parser#opt registers an option it infers the option type from the class of the :default value; the case at trollop.rb:188-213 only accepts nil, Integer, other Numeric, TrueClass/FalseClass, String, IO, and Date (Array defaults go through a separate branch). A default of any other class falls into the else branch at line 212 and raises ArgumentError. This is a declaration-time developer error raised before any command line is parsed.
Source
Thrown at lib/puppet/util/command_line/trollop.rb:212
when IO; :io
when Date; :date
when Array
if opts[:default].empty?
raise ArgumentError, _("multiple argument type cannot be deduced from an empty array for '%{value0}'") % { value0: opts[:default][0].class.name }
end
case opts[:default][0] # the first element determines the types
when Integer; :ints
when Numeric; :floats
when String; :strings
when IO; :ios
when Date; :dates
else
raise ArgumentError, _("unsupported multiple argument type '%{value0}'") % { value0: opts[:default][0].class.name }
end
when nil; nil
else
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]]View on GitHub (pinned to e227c27540)
Solutions
- Use a supported default class: String, Integer, Float, true/false, IO, Date, or an Array of those
- Drop :default and declare :type explicitly (e.g. `type: :string`), handling nil where the value is consumed
- For array defaults, make sure the first element is Integer/Numeric/String/IO/Date so the multi type can be deduced (otherwise the 'unsupported multiple argument type' variant at line 208 fires)
- Pass complex values as strings and decode them in a :callback block
Example fix
# before opt :mode, 'Execution mode', default: :fast # after opt :mode, 'Execution mode', type: :string, default: 'fast'
Defensive patterns
Strategy: validation
Validate before calling
# Validate an option hash's :default before handing it to Parser#opt
SUPPORTED_DEFAULT_CLASSES = [Integer, Numeric, TrueClass, FalseClass, String, IO, Date]
def supported_default?(default)
default.nil? ||
SUPPORTED_DEFAULT_CLASSES.any? { |k| default.is_a?(k) } ||
(default.is_a?(Array) && !default.empty? && supported_default?(default.first))
end
raise ArgumentError, "unsupported default #{opts[:default].class}" unless supported_default?(opts[:default]) Type guard
def trollop_default_type(default)
case default
when Integer then :int
when Numeric then :float
when true, false then :flag
when String then :string
when IO then :io
when Date then :date
when Array then %i[ints floats strings ios dates].find { |t| trollop_default_type(default.first).to_s.start_with?(t.to_s[0...-1]) || trollop_default_type(default.first) == t.to_s.singularize.to_sym }
end
end
# returns nil for unsupported classes (e.g. Symbol, Hash) - treat nil as 'will raise' Try / catch
# Declaration-time errors are ArgumentError; catch them while building the parser so one bad option does not kill the whole face load:
begin
parser.opt :mode, 'Mode', default: raw_default
rescue ArgumentError => e
raise "Invalid option declaration (:mode): #{e.message}"
end Prevention
- Restrict option defaults to String, Integer, Float, boolean, IO, Date, or arrays of those
- When defaults come from YAML/ENV, coerce them to the intended class at load time
- Add a unit test per declared option that instantiates the parser - declaration errors surface immediately in CI
When it happens
Trigger: Calling `opt :mode, 'Mode', default: :fast` (Symbol), `default: {}` (Hash), `default: Time.now`, or `default: 1..5` (Range). Also a Hash default used together with :multi, since arrays are the only collection with type deduction.
Common situations: Writing a Puppet face or application and reusing option hashes written for Ruby's OptionParser, where arbitrary default objects were fine; defaults loaded from YAML that deserialize into unexpected classes; forgetting that only Integer/Float/boolean/String/IO/Date and arrays of those are supported.
Related errors
- invalid long option name %{name}
- invalid short option name '%{name}'
- a short option name can't be a number or a dash
- :type specification and default type don't match (default ty
- long option name %{value0} is already taken; please specify
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/bec852dea9c2f799.
Report an issue: GitHub.