{"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":"error","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/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/dag/dag.go#L220-L256","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Read the cycle list in the error — it names every participating resource/module in dependency order.","Break the cycle by removing the offending depends_on entry or restructuring the resources so the dependency is one-directional.","If the cycle is between modules, flatten or restructure the module call hierarchy.","Use 'terraform graph' to visualize the dependency graph and confirm the cycle is gone after the edit."],"exampleFix":"// before: mutual dependency\nresource \"a\" \"x\" { depends_on = [a.y] }\nresource \"a\" \"y\" { depends_on = [a.x] }\n\n// after: break the cycle\nresource \"a\" \"x\" { }\nresource \"a\" \"y\" { depends_on = [a.x] }","handlingStrategy":"validation","validationCode":"// Before calling Validate, ensure no multi-vertex cycle exists.\nfunc hasCycle(g *dag.AcyclicGraph) bool {\n    return len(g.Cycles()) > 0\n}","typeGuard":null,"tryCatchPattern":"if err := g.Validate(); err != nil {\n    // err lists every cycle as a vertex chain; surface to the user as a config error.\n    return fmt.Errorf(\"configuration has dependency cycles: %w\", err)\n}","preventionTips":["Avoid mutual depends_on between resources; make dependency direction explicit and one-way.","Use 'terraform graph' to inspect the dependency graph after structural config changes.","Audit module includes for indirect cycles."],"tags":["dag","cycle","dependency-graph","terraform-core","go"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}