puppetlabs/puppet · critical

Found %{num} dependency cycles:\n

Error message

Found %{num} dependency cycles:\n

What it means

Built by Puppet::Graph::SimpleGraph cycle reporting when the catalog's dependency graph contains cycles: require/before/notify/subscribe edges forming loops, often through containers or resource collections. The message lists each cycle path and points at the --graph .dot output; the run then fails because the resources cannot be ordered.

Source

Thrown at lib/puppet/graph/simple_graph.rb:247

    cycles = find_cycles_in_graph
    number_of_cycles = cycles.length
    return if number_of_cycles == 0

    message = n_("Found %{num} dependency cycle:\n", "Found %{num} dependency cycles:\n", number_of_cycles) % { num: number_of_cycles }

    cycles.each do |cycle|
      paths = paths_in_cycle(cycle)
      message += paths.map { |path| '(' + path.join(' => ') + ')' }.join('\n') + '\n'
    end

    if Puppet[:graph] then
      filename = write_cycles_to_graph(cycles)
      message += _("Cycle graph written to %{filename}.") % { filename: filename }
    else
      # TRANSLATORS '--graph' refers to a command line option and OmniGraffle and GraphViz are program names and should not be translated
      message += _("Try the '--graph' option and opening the resulting '.dot' file in OmniGraffle or GraphViz")
    end
    Puppet.err(message)
    cycles
  end

  def write_cycles_to_graph(cycles)
    # This does not use the DOT graph library, just writes the content
    # directly.  Given the complexity of this, there didn't seem much point
    # using a heavy library to generate exactly the same content. --daniel 2011-01-27
    graph = ["digraph Resource_Cycles {"]
    graph << '  label = "Resource Cycles"'

    cycles.each do |cycle|
      paths_in_cycle(cycle, 10).each do |path|
        graph << path.map { |v| '"' + v.to_s.gsub(/"/, '\\"') + '"' }.join(" -> ")
      end
    end

    graph << '}'

View on GitHub (pinned to e227c27540)

Solutions

  1. Run once with `puppet agent -t --graph` and open the written .dot file in GraphViz or OmniGraffle to see the loop
  2. Express each ordering in one direction only — use require OR before for a pair, never both
  3. Check class containment and run stages: avoid Class['x'] requiring Class['y'] when y already contains or requires x
  4. Simplify relationship collectors and chained arrows around the resources named in the cycle

Example fix

# before
class { 'apache': require => Class['app'] }
class { 'app':   require => Class['apache'] }

# after — single direction
class { 'apache': }
class { 'app': require => Class['apache'] }
Defensive patterns

Strategy: validation

Validate before calling

# spec/classes/site_spec.rb (rspec-puppet)
require 'spec_helper'

describe 'site' do
  it 'compiles without dependency cycles' do
    is_expected.to compile.with_all_deps   # fails the spec when the catalog has cycles
  end
end

Try / catch

begin
  catalog = compiler.compile
rescue Puppet::Error => e
  raise unless e.message =~ /dependency cycles/
  run_with_graph!             # re-run `puppet agent -t --graph`, then inspect the .dot
  raise
end

Prevention

When it happens

Trigger: A catalog in which resources mutually depend: A requires B while B requires A, directly or through classes, defined-type containers, stages, or relationship collectors like Resource <| |>. The graph is acyclic-checked during catalog application and report_cycle prints each loop.

Common situations: Profiles that both require and are required; require plus before expressed on the same pair; stage relationships mixed with class containment; an added -> chain that closes a loop; exported-resource collectors creating unexpected edges.

Related errors


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