puppetlabs/puppet · error · ArgumentError
:type specification and default type don't match (default ty
Error message
:type specification and default type don't match (default type is %{type_from_default}) What it means
When Parser#opt receives both :type and :default, Trollop derives a second type symbol from the default's class (type_from_default) and compares it with the declared :type at trollop.rb:215. If they disagree, opt raises ArgumentError rather than silently coercing the default. Type aliases (:boolean/:bool, :integer, :integers, :double, :doubles) are normalized before the check, so only genuine class/type mismatches fire.
Source
Thrown at lib/puppet/util/command_line/trollop.rb:215
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]]
## fill in :short
unless opts[:short] == :noneView on GitHub (pinned to e227c27540)
Solutions
- Make the default's class agree with the declared :type (`default: 8080` for :int)
- Convert at declaration time: `default: ENV['PORT'] && ENV['PORT'].to_i`
- Omit :type and let Trollop infer it from the default
- Omit :default and handle nil where the option is consumed
Example fix
# before opt :port, 'Server port', type: :int, default: ENV['PORT'] # ENV values are Strings -> mismatch # after opt :port, 'Server port', type: :int, default: ENV['PORT']&.to_i
Defensive patterns
Strategy: validation
Validate before calling
# Check that :type agrees with the class of :default before calling opt
EXPECTED_TYPE = { Integer => :int, Float => :float, String => :string,
TrueClass => :flag, FalseClass => :flag, IO => :io, Date => :date }
def type_matches_default?(type, default)
base = type.to_s.sub('s', '').to_sym # :ints -> :int, :floats -> :float
sample = default.is_a?(Array) ? default.first : default
EXPECTED_TYPE[sample.class] == base
end
abort "type/default mismatch" if opts[:type] && opts[:default] && !type_matches_default?(opts[:type], opts[:default]) Type guard
def inferred_type(default)
{ Integer => :int, Float => :float, String => :string,
TrueClass => :flag, FalseClass => :flag, IO => :io, Date => :date }[default.class]
end
# Use inferred_type(default) as the :type you declare, or omit :type entirely Try / catch
begin parser.opt :port, 'Port', type: :int, default: raw rescue ArgumentError => e # re-declare with the default converted to the declared type parser.opt :port, 'Port', type: :int, default: Integer(raw) end
Prevention
- Never mix a string default (ENV/YAML sourced) with a numeric :type - coerce first (to_i/to_f)
- Prefer declaring only one of :type or :default and letting Trollop infer the other
- Cover each option declaration with a parser-construction unit test
When it happens
Trigger: `opt :port, 'Port', type: :int, default: '8080'` (String default vs :int); `type: :string, default: 5`; `type: :flag, default: 'yes'`; `type: :ints, default: [1.5]` (Float elements infer :floats).
Common situations: Defaults sourced from ENV or YAML so they arrive as strings (`default: ENV['PORT']`); copy-pasting a default from another option with a different type; refactoring an option's type without updating its default.
Related errors
- unsupported argument type '%{value0}'
- invalid long option name %{name}
- long option name %{value0} is already taken; please specify
- invalid short option name '%{name}'
- short option name %{value0} is already taken; please specify
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/3ad76b79c1c18374.
Report an issue: GitHub.