puppetlabs/puppet · error · ArgumentError
Invalid option '%{option}'
Error message
Invalid option '%{option}' What it means
Fileset's initialize_from_hash dynamically calls `<option>=` for every key in the options hash. A key with no corresponding setter raises NoMethodError, which is re-raised as ArgumentError "Invalid option" with the original backtrace. Valid options map to existing attribute writers: path, ignore, links, recurse, recurselimit, max_files, checksum_type.
Source
Thrown at lib/puppet/file_serving/fileset.rb:108
def links=(links)
links = links.to_sym
# TRANSLATORS ":links" is a parameter name and should not be translated
raise(ArgumentError, _("Invalid :links value '%{links}'") % { links: links }) unless [:manage, :follow].include?(links)
@links = links
@stat_method = @links == :manage ? :lstat : :stat
end
private
def initialize_from_hash(options)
options.each do |option, value|
method = option.to_s + "="
begin
send(method, value)
rescue NoMethodError => e
raise ArgumentError, _("Invalid option '%{option}'") % { option: option }, e.backtrace
end
end
end
def initialize_from_request(request)
[:links, :ignore, :recurse, :recurselimit, :max_files, :checksum_type].each do |param|
if request.options.include?(param) # use 'include?' so the values can be false
value = request.options[param]
elsif request.options.include?(param.to_s)
value = request.options[param.to_s]
end
next if value.nil?
value = true if value == "true"
value = false if value == "false"
value = Integer(value) if value.is_a?(String) and value =~ /^\d+$/
send(param.to_s + "=", value)
endView on GitHub (pinned to e227c27540)
Solutions
- Check the key against the supported set (path, ignore, links, recurse, recurselimit, max_files, checksum_type) and fix the typo
- Whitelist keys before constructing: slice the hash to the known option names
- If you meant request-style options, pass a Puppet::Indirector::Request (initialize_from_request only reads known params) instead of a raw hash
Example fix
# before
opts = { recurse: true, recurselimit: 2, ignore_fire: '.git' }
fileset = Puppet::FileServing::Fileset.new('/srv/data', opts)
# after
opts = { recurse: true, recurselimit: 2, ignore: '.git' }
fileset = Puppet::FileServing::Fileset.new('/srv/data', opts) Defensive patterns
Strategy: validation
Validate before calling
ALLOWED = %i[path ignore links recurse recurselimit max_files checksum_type].freeze opts = opts.slice(*ALLOWED) # Hash#slice (Ruby 2.5+) fileset = Puppet::FileServing::Fileset.new(path, opts)
Type guard
def valid_fileset_options?(opts)
opts.is_a?(Hash) && opts.keys.all? { |k| ALLOWED.include?(k.to_sym) }
end Try / catch
begin
Puppet::FileServing::Fileset.new(path, opts)
rescue ArgumentError => e
raise unless e.message.start_with?("Invalid option")
bad = opts.keys.find { |k| !ALLOWED.include?(k.to_sym) }
opts = opts.reject { |k, _| k.to_sym == bad.to_sym }
retry
end Prevention
- Pass option hashes you construct, not ones you received for other APIs
- Whitelist keys at deserialization boundaries (YAML/JSON config)
- Pin the allowed-key list near the Fileset call and update it on Puppet upgrades
When it happens
Trigger: Puppet::FileServing::Fileset.new('/x', recurse_limit: 2) (typo'd key); passing a generic options hash (from YAML/JSON or method args splats) that contains keys like `server` or `environment` that Fileset does not support.
Common situations: Forwarding option hashes meant for other classes into Fileset; typo'd symbol keys; configuration-driven code where the set of keys drifts from the Fileset API after a Puppet upgrade.
Related errors
- Fileset paths must be fully qualified: %{path}
- Fileset paths must exist
- Invalid entry at %{error_location}: '%{file_text}'
- %{mount} is already mounted at %{name} at %{error_location}
- Fileset recurse parameter must not be a number anymore, plea
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/a4cfab289fceeda9.
Report an issue: GitHub.