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
- Reproduce with puppet apply --noop --trace and enable debug logging to see which generator keeps iterating ('Iterated (N) on generators' profile messages)
- Inspect recently changed defines for self-instantiation and break the cycle (fixed set of titles, restructure as classes)
- 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
- Never instantiate a define from inside itself with generated titles
- Watch 'Iterated (N) on generators' profiler messages in debug output during development
- Smoke-test changed defines with puppet apply --noop --evaltrace before rollout
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
- Relative paths must not be fully qualified
- Fileset recurse parameter must not be a number anymore, plea
- The directory '%{path}' contains %{entries} entries, which e
- Function Load Error for function '%{function_name}': %{messa
- A required parameter cannot be added after an optional param
AI-assisted analysis of puppetlabs/puppet@e227c27540 (2026-08-21).
Data as JSON: /api/errors/e2db86da2af72495.
Report an issue: GitHub.