{"record":{"id":"4f59418903def8df","repo":"hashicorp/terraform","slug":"cycle-s","errorCode":null,"errorMessage":"Cycle:\n  %s","messagePattern":"Cycle:\n  (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/dag/dag.go","lineNumber":238,"sourceCode":"\t\t\t// compare lexically.\n\t\t\tfirst := 0\n\t\t\tfor i := 1; i < len(cycleStr); i++ {\n\t\t\t\tif len(cycleStr[i]) < len(cycleStr[first]) {\n\t\t\t\t\tfirst = i\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\n\t\t\t\tif len(cycleStr[i]) == len(cycleStr[first]) && cycleStr[i] < cycleStr[first] {\n\t\t\t\t\tfirst = i\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// pivot the slice around our new first index\n\t\t\tif first > 0 {\n\t\t\t\tcycleStr = append(cycleStr[first:], cycleStr[:first]...)\n\t\t\t}\n\n\t\t\terr = errors.Join(err, fmt.Errorf(\n\t\t\t\t\"Cycle:\\n  %s\", strings.Join(cycleStr, \"\\n  \"),\n\t\t\t))\n\t\t}\n\t}\n\n\t// Look for cycles to self\n\tfor _, e := range g.Edges() {\n\t\tif e.Source == e.Target {\n\t\t\terr = errors.Join(err, fmt.Errorf(\n\t\t\t\t\"Self reference: %s\", e.Source.Name()))\n\t\t}\n\t}\n\n\treturn err\n}\n\n// Cycles reports any cycles between graph nodes.\n// Self-referencing nodes are not reported, and must be detected separately.","sourceCodeStart":220,"sourceCodeEnd":256,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/dag/dag.go#L220-L256","documentation":"Returned by AcyclicGraph.Validate() (dag.go:238) when the graph contains a strongly connected component of length > 1 — i.e. a genuine cycle where vertices depend on each other in a loop. The message lists the vertex names forming the cycle (reversed and pivoted for readability). An AcyclicGraph must be acyclic to be walkable, so this is a hard validation failure.","triggerScenarios":"Calling Validate() on an AcyclicGraph (used for Terraform's resource dependency graph) after adding edges that form a loop — e.g. resource A depends on B, B depends on C, C depends on A. Terraform runs this during plan when resolving resource dependencies.","commonSituations":"Circular resource dependencies in configuration (e.g. two resources each reference an attribute of the other via depends_on or interpolation). A provider or module that wires up graph edges forming a loop. Importing resources whose recorded dependencies loop. Incorrect use of depends_on creating an artificial cycle.","solutions":["Read the cycle path in the message (each line is a vertex name) — these resources mutually depend on each other; break the loop by removing one depends_on or restructuring the references.","Use terraform graph to visualize the dependency graph and locate the cycle visually.","Decouple resources by splitting one into a data source or by removing a cross-reference that closes the loop.","Check for accidental self-referential module/resource includes or a depends_on that points back upstream."],"exampleFix":"// before — resource_a depends_on [resource_b] AND resource_b depends_on [resource_a]\n\n// after — break the cycle: remove one direction\nresource \"x\" \"a\" { /* no depends_on to b */ }\nresource \"x\" \"b\" { depends_on = [x.a] }","handlingStrategy":"validation","validationCode":"// Detect cycles before Validate() surfaces them as plan errors\nfunc hasCycle(g *dag.AcyclicGraph) bool {\n    return len(g.Cycles()) > 0\n}\n// Cycles() returns the vertex loops; inspect them to break dependencies proactively","typeGuard":"func isAcyclic(g *dag.AcyclicGraph) bool {\n    return len(g.Cycles()) == 0\n}","tryCatchPattern":"if err := graph.Validate(); err != nil {\n    log.Printf(\"[ERROR] dependency graph invalid: %v\", err)\n    return err // surface the cycle path to the user for resolution\n}","preventionTips":["Avoid bidirectional depends_on between resources.","Use 'terraform graph' to visualize dependencies and catch loops early.","If two resources truly need each other's outputs, split one into a data source."],"tags":["dag","cycle","dependency-graph","depends-on","terraform-core"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T20:17:04.800Z"}