puppetlabs/puppet · error · Puppet::Error

The directory '%{path}' contains %{entries} entries, which e

Error message

The directory '%{path}' contains %{entries} entries, which exceeds the limit of %{munged_max_files} specified by the max_files parameter for this resource. The limit may be increased, but be aware that large number of file resources can result in excessive resource consumption and degraded performance. Consider using an alternate method to manage large directory trees

What it means

Fileset#files recursively collects entries, then enforces the resource's max_files: if max_files > 0 (note '-1' as a string is munged to unlimited) and files.size exceeds it, a hard Puppet::Error is raised. With the default max_files of 0 only a soft warning fires past 1000 entries. This protects agent and master from resource exhaustion when managing huge trees.

Source

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

    raise ArgumentError, _("Fileset paths must exist") unless valid?(path)
    # TRANSLATORS "recurse" and "recurselimit" are parameter names and should not be translated
    raise ArgumentError, _("Fileset recurse parameter must not be a number anymore, please use recurselimit") if @recurse.is_a?(Integer)
  end

  # Return a list of all files in our fileset.  This is different from the
  # normal definition of find in that we support specific levels
  # of recursion, which means we need to know when we're going another
  # level deep, which Find doesn't do.
  def files
    files = perform_recursion
    soft_max_files = 1000

    # munged_max_files is needed since puppet http handler is keeping negative numbers as strings
    # https://github.com/puppetlabs/puppet/blob/main/lib/puppet/network/http/handler.rb#L196-L197
    munged_max_files = max_files == '-1' ? -1 : max_files

    if munged_max_files > 0 && files.size > munged_max_files
      raise Puppet::Error, _("The directory '%{path}' contains %{entries} entries, which exceeds the limit of %{munged_max_files} specified by the max_files parameter for this resource. The limit may be increased, but be aware that large number of file resources can result in excessive resource consumption and degraded performance. Consider using an alternate method to manage large directory trees") % { path: path, entries: files.size, munged_max_files: munged_max_files }
    elsif munged_max_files == 0 && files.size > soft_max_files
      Puppet.warning _("The directory '%{path}' contains %{entries} entries, which exceeds the default soft limit %{soft_max_files} and may cause excessive resource consumption and degraded performance. To remove this warning set a value for `max_files` parameter or consider using an alternate method to manage large directory trees") % { path: path, entries: files.size, soft_max_files: soft_max_files }
    end

    # Now strip off the leading path, so each file becomes relative, and remove
    # any slashes that might end up at the beginning of the path.
    result = files.collect { |file| file.sub(%r{^#{Regexp.escape(@path)}/*}, '') }

    # And add the path itself.
    result.unshift(".")

    result
  end

  def ignore=(values)
    values = [values] unless values.is_a?(Array)
    @ignore = values.collect(&:to_s)
  end

View on GitHub (pinned to e227c27540)

Solutions

  1. Raise `max_files` on the resource to comfortably above the real entry count (or set it to -1 for unlimited, accepting the risk)
  2. Reduce the tree: exclude subdirectories with `ignore`, split the content across several narrower resources, or serve fewer files
  3. For very large trees, switch strategy: ship a tarball/archive and expand it (puppet-archive, exec + tar) instead of per-file resources
  4. If you only wanted the warning gone, keep max_files >= the entry count rather than unbounded

Example fix

# before
file { '/usr/share/app':
  ensure    => directory,
  source    => 'puppet:///modules/app/share',
  recurse   => true,
  max_files => 100,
}

# after
file { '/usr/share/app':
  ensure    => directory,
  source    => 'puppet:///modules/app/share',
  recurse   => true,
  max_files => 5000,
}
Defensive patterns

Strategy: validation

Validate before calling

# Estimate the tree size before committing to a max_files
entries = Dir.glob(File.join(path, '**', '*'), File::FNM_DOTMATCH).size
max_files = 1000 if max_files.is_a?(Integer) && max_files > 0 && max_files < entries
# or fail fast with a clear message of your own

Try / catch

begin
  fileset.files
rescue Puppet::Error => e
  raise unless e.message.include?('exceeds the limit') && e.message.include?('max_files')
  raise unless retried_once # decide: bump max_files or split the tree; do not loop blindly
  max_files = -1
  retry
end

Prevention

When it happens

Trigger: `file { '/big': source => 'puppet:///mod/big', recurse => true, max_files => 100 }` where the served directory holds more than 100 entries; recursive file resources over vendor blobs, node_modules-style trees, or log directories; max_files carried over from request options as a small integer.

Common situations: Pointing a recursive file resource at a large data directory (images, caches, package trees); lowering max_files to silence the 1000-entry soft warning and then hitting the hard limit; upgrading modules that suddenly ship many more files.

Related errors


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