{"record":{"id":"ea7f34c430c6c0fa","repo":"hashicorp/terraform","slug":"self-reference-s","errorCode":null,"errorMessage":"Self reference: %s","messagePattern":"Self reference: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"internal/dag/dag.go","lineNumber":247,"sourceCode":"\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.\nfunc (g *AcyclicGraph) Cycles() [][]Vertex {\n\tvar cycles [][]Vertex\n\tfor _, cycle := range StronglyConnected(&g.Graph) {\n\t\tif len(cycle) > 1 {\n\t\t\tcycles = append(cycles, cycle)\n\t\t}\n\t}\n\treturn cycles\n}","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/hashicorp/terraform/blob/c9def3e214014c1188faabfc4a5bde5095139765/internal/dag/dag.go#L229-L265","documentation":"Returned by AcyclicGraph.Validate() (dag.go:247) when an edge exists whose Source vertex equals its Target vertex — a vertex that depends on itself. Unlike multi-vertex cycles (detected separately via strongly connected components), self-loops are checked directly by iterating edges; a self-edge is always invalid in an acyclic graph.","triggerScenarios":"A resource or graph node has an edge pointing to itself (e.Source == e.Target). In Terraform terms, a resource whose depends_on or reference graph includes itself, or programmatic DAG construction that added Edge(v, v).","commonSituations":"A resource lists itself in depends_on. A module/resource name collision causing a reference to resolve to the same node. Programmatic graph builders that add an edge from a node to itself. Copy-paste in dependency wiring.","solutions":["Read the vertex name in the message; find that resource/module in config and remove the self-reference (e.g. remove itself from its depends_on list).","Run terraform graph and look for a node with an edge looping back to itself.","If building the DAG programmatically, guard against adding Edge(v, v).","Rename one of two colliding resources so the reference resolves to a distinct node."],"exampleFix":"// before\nresource \"aws_instance\" \"web\" {\n  depends_on = [aws_instance.web] // self reference\n}\n\n// after — remove the self reference\nresource \"aws_instance\" \"web\" {\n  depends_on = [aws_instance.db]\n}","handlingStrategy":"validation","validationCode":"// Reject self-edges before validating/walking the graph\nfunc hasSelfEdge(g *dag.AcyclicGraph) bool {\n    for _, e := range g.Edges() {\n        if e.Source == e.Target {\n            return true\n        }\n    }\n    return false\n}","typeGuard":"func hasSelfEdge(g *dag.AcyclicGraph) bool {\n    for _, e := range g.Edges() {\n        if e.Source == e.Target {\n            return true\n        }\n    }\n    return false\n}","tryCatchPattern":null,"preventionTips":["Never list a resource in its own depends_on.","If building a DAG programmatically, guard g.Edge(v, v) before adding.","Run Validate() on constructed graphs before Walk()."],"tags":["dag","self-reference","dependency-graph","depends-on"],"analyzedSha":"c9def3e214014c1188faabfc4a5bde5095139765","analyzedAt":"2026-08-07T15:39:49.278Z","schemaVersion":2},"datasetVersion":"2026-08-07T21:17:07.882Z"}