puppetlabs/puppet · error · ArgumentError

Fileset paths must be fully qualified: %{path}

Error message

Fileset paths must be fully qualified: %{path}

What it means

Puppet::FileServing::Fileset#initialize chomps a trailing separator (special-casing Windows drive roots like `C:/`) and then requires Puppet::Util.absolute_path?(path) to be true. Relative paths cannot be resolved against a well-known base, so the constructor raises ArgumentError before any options are applied.

Source

Thrown at lib/puppet/file_serving/fileset.rb:36

    result = {}

    filesets.each do |fileset|
      fileset.files.each do |file|
        result[file] ||= fileset.path
      end
    end

    result
  end

  def initialize(path, options = {})
    if Puppet::Util::Platform.windows?
      # REMIND: UNC path
      path = path.chomp(File::SEPARATOR) unless path =~ %r{^[A-Za-z]:/$}
    else
      path = path.chomp(File::SEPARATOR) unless path == File::SEPARATOR
    end
    raise ArgumentError, _("Fileset paths must be fully qualified: %{path}") % { path: path } unless Puppet::Util.absolute_path?(path)

    @path = path

    # Set our defaults.
    self.ignore = []
    self.links = :manage
    @recurse = false
    @recurselimit = :infinite
    @max_files = 0

    if options.is_a?(Puppet::Indirector::Request)
      initialize_from_request(options)
    else
      initialize_from_hash(options)
    end

    raise ArgumentError, _("Fileset paths must exist") unless valid?(path)
    # TRANSLATORS "recurse" and "recurselimit" are parameter names and should not be translated

View on GitHub (pinned to e227c27540)

Solutions

  1. Expand the path before constructing: File.expand_path(p) (or File.join(base_dir, p)) so it becomes absolute
  2. On Windows, make sure the path includes the drive letter (e.g. `C:/srv/data`)
  3. Validate inputs at the boundary of your tooling with Puppet::Util.absolute_path? and reject/normalize relative paths early

Example fix

# before
fileset = Puppet::FileServing::Fileset.new('modules/foo', recurse: true)

# after
fileset = Puppet::FileServing::Fileset.new(File.expand_path('modules/foo'), recurse: true)
Defensive patterns

Strategy: validation

Validate before calling

def fileset_path!(p)
  raise ArgumentError, "relative path: #{p}" unless Puppet::Util.absolute_path?(p)
  p
end

path = fileset_path!(user_supplied_path)
fileset = Puppet::FileServing::Fileset.new(path, options)

Type guard

# Narrow arbitrary input to an absolute path String before use
def absolute_path_string?(v)
  v.is_a?(String) && Puppet::Util.absolute_path?(v)
end

Try / catch

begin
  Puppet::FileServing::Fileset.new(path, options)
rescue ArgumentError => e
  raise unless e.message.start_with?('Fileset paths must be fully qualified')
  retry_with = File.expand_path(path) # or log & reject
end

Prevention

When it happens

Trigger: Calling Puppet::FileServing::Fileset.new('modules/foo', ...) or Fileset.new('relative/dir') with a path that has no leading `/` (or drive letter on Windows); building a fileset from user-supplied or interpolated strings that were never expanded.

Common situations: Scripts that construct filesets from relative paths assuming the process cwd; porting Unix code to Windows where the path lacks a drive letter; options hashes deserialized from requests where the path lost its leading slash.

Related errors


AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21). Data as JSON: /api/errors/5c25f0df1d5f72cb. Report an issue: GitHub.