{"record":{"id":"aea9b0dd705ec904","repo":"opentofu/opentofu","slug":"self-reference-s","errorCode":null,"errorMessage":"Self reference: %s","messagePattern":"Self reference: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/dag/dag.go","lineNumber":145,"sourceCode":"\t// Look for cycles of more than 1 component\n\tvar err error\n\tcycles := g.Cycles()\n\tif len(cycles) > 0 {\n\t\tfor _, cycle := range cycles {\n\t\t\tcycleStr := make([]string, len(cycle))\n\t\t\tfor j, vertex := range cycle {\n\t\t\t\tcycleStr[j] = VertexName(vertex)\n\t\t\t}\n\n\t\t\terr = multierror.Append(err, fmt.Errorf(\n\t\t\t\t\"Cycle: %s\", strings.Join(cycleStr, \", \")))\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 = multierror.Append(err, fmt.Errorf(\n\t\t\t\t\"Self reference: %s\", VertexName(e.Source())))\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":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/opentofu/opentofu/blob/3561785c48c1ce615e7c50261bd351f26053efa2/internal/dag/dag.go#L127-L163","documentation":"Validate()'s second pass scans raw edges for source == target and reports 'Self reference: <vertex name>'. Cycles() deliberately does not report single-vertex strongly connected components, so self-edges get a dedicated check. In configuration terms: a node that depends on itself - a resource whose depends_on includes its own address, or graph-transformer code that adds the current node into its own dependency set.","triggerScenarios":"g.AddEdge(v, v) - any edge whose source and target are the same vertex; a depends_on list containing the resource's own address; generator code copying a node into its own dependencies.","commonSituations":"Templated depends_on lists that accidentally include the resource itself; copy-pasting an address into its own block; transformers forwarding the current node into a dependency set.","solutions":["Locate the named vertex and delete the self edge (remove the self-referencing depends_on entry)","In generator/transform code, filter e.Source() == e.Target() before calling AddEdge","Re-run Validate() to catch remaining multi-vertex cycles (error 718) in the same pass"],"exampleFix":"// before\ng.AddEdge(v, v)\n\n// after\n// (edge removed entirely, or corrected to the intended dependency)\ng.AddEdge(v, dep)","handlingStrategy":"validation","validationCode":"for _, e := range g.Edges() {\n\tif e.Source() == e.Target() {\n\t\treturn fmt.Errorf(\"self reference: %s\", dag.VertexName(e.Source()))\n\t}\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Filter self-edges in generators: skip AddEdge(v, v)","Lint depends_on lists against the containing resource's own address"],"tags":["dag","graph","self-reference","validation"],"backgroundTag":null,"analyzedSha":"3561785c48c1ce615e7c50261bd351f26053efa2","analyzedAt":"2026-08-15T23:27:16.226Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}