hashicorp/terraform · error

Cycle

Error message

Cycle:
  %s

What it means

Returned by AcyclicGraph.Validate when one or more strongly-connected components of length >= 2 exist in the graph — i.e. a real cycle. The cycle is rendered as an indented list of vertex names, normalized to start from the shortest/lexicographically-first vertex for stable output. Multiple cycles are joined into the same error via errors.Join.

Solutions

  1. Read the cycle list in the error — it names every participating resource/module in dependency order.
  2. Break the cycle by removing the offending depends_on entry or restructuring the resources so the dependency is one-directional.
  3. If the cycle is between modules, flatten or restructure the module call hierarchy.
  4. Use 'terraform graph' to visualize the dependency graph and confirm the cycle is gone after the edit.

Example fix

// before: mutual dependency
resource "a" "x" { depends_on = [a.y] }
resource "a" "y" { depends_on = [a.x] }

// after: break the cycle
resource "a" "x" { }
resource "a" "y" { depends_on = [a.x] }
Defensive patterns

Strategy: validation

Validate before calling

// Before calling Validate, ensure no multi-vertex cycle exists.
func hasCycle(g *dag.AcyclicGraph) bool {
    return len(g.Cycles()) > 0
}

Try / catch

if err := g.Validate(); err != nil {
    // err lists every cycle as a vertex chain; surface to the user as a config error.
    return fmt.Errorf("configuration has dependency cycles: %w", err)
}

Prevention

When it happens

Trigger: Calling AcyclicGraph.Validate() on a graph whose edges form a cycle (A->B->A or longer). Surfaces during Terraform's plan/apply graph validation when resources depend on each other in a loop (e.g. two resources each depend on the other via depends_on or implicit references).

Common situations: Mutual depends_on between two resources; circular module includes; provider/resource dependency loops introduced by templating or refactoring; config edits that create indirect cycles through data sources.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/4f59418903def8df. Report an issue: GitHub.

Appendix: source

Thrown at internal/dag/dag.go:238

			// compare lexically.
			first := 0
			for i := 1; i < len(cycleStr); i++ {
				if len(cycleStr[i]) < len(cycleStr[first]) {
					first = i
					continue
				}

				if len(cycleStr[i]) == len(cycleStr[first]) && cycleStr[i] < cycleStr[first] {
					first = i
				}
			}

			// pivot the slice around our new first index
			if first > 0 {
				cycleStr = append(cycleStr[first:], cycleStr[:first]...)
			}

			err = errors.Join(err, fmt.Errorf(
				"Cycle:\n  %s", strings.Join(cycleStr, "\n  "),
			))
		}
	}

	// Look for cycles to self
	for _, e := range g.Edges() {
		if e.Source == e.Target {
			err = errors.Join(err, fmt.Errorf(
				"Self reference: %s", e.Source.Name()))
		}
	}

	return err
}

// Cycles reports any cycles between graph nodes.
// Self-referencing nodes are not reported, and must be detected separately.

View on GitHub (pinned to d32a084675)