puppetlabs/puppet · error · Puppet::ParseError

Somehow looped more than 1000 times while evaluating host ca

Error message

Somehow looped more than 1000 times while evaluating host catalog

What it means

Catalog evaluation iterates over collections and definitions in passes until a pass adds no new work (done stays true). A counter caps the loop at 1000 passes; exceeding it raises Puppet::ParseError, guarding against non-converging catalog generation - effectively an infinite loop during compile, usually a definition that keeps instantiating more resources forever.

Source

Thrown at lib/puppet/parser/compiler.rb:383

  # and defined resources can generate new resources, which themselves could
  # be defined resources.
  def evaluate_generators
    count = 0
    loop do
      done = true

      Puppet::Util::Profiler.profile(_("Iterated (%{count}) on generators") % { count: count + 1 }, [:compiler, :iterate_on_generators]) do
        # Call collections first, then definitions.
        done = false if evaluate_collections
        done = false if evaluate_definitions
      end

      break if done

      count += 1

      if count > 1000
        raise Puppet::ParseError, _("Somehow looped more than 1000 times while evaluating host catalog")
      end
    end
  end
  protected :evaluate_generators

  # Find and evaluate our main object, if possible.
  def evaluate_main
    krt = environment.known_resource_types
    @main = krt.find_hostclass('') || krt.add(Puppet::Resource::Type.new(:hostclass, ''))
    @topscope.source = @main
    @main_resource = Puppet::Parser::Resource.new('class', :main, :scope => @topscope, :source => @main)
    @topscope.resource = @main_resource

    add_resource(@topscope, @main_resource)

    @main_resource.evaluate
  end

View on GitHub (pinned to e227c27540)

Solutions

  1. Reproduce with puppet apply --noop --trace and enable debug logging to see which generator keeps iterating ('Iterated (N) on generators' profile messages)
  2. Inspect recently changed defines for self-instantiation and break the cycle (fixed set of titles, restructure as classes)
  3. Replace recursion with iteration (each blocks) inside a single define

Example fix

// before
define app::chain($n) { app::chain { "${n}-a": n => "${n}-a" } }

// after
define app::chain($parts) { $parts.each |$p| { file { "${title}-${p}": ensure => present } } }
Defensive patterns

Strategy: try-catch

Try / catch

begin
  compiler.compile
rescue Puppet::ParseError => e
  raise NonConvergingCatalog, e.message if e.message.include?('looped more than 1000 times')
  raise
end

Prevention

When it happens

Trigger: A defined type that (directly or through a cycle of other defines) instantiates itself with ever-new titles; virtual resource collections that generate additional virtual resources each pass; definitions whose evaluation re-triggers the same generator.

Common situations: Recursive defines (define a { a { "${title}-x": } }); module upgrades introducing cyclic generation; collectors that expand into new collector-matching resources each round.

Related errors


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