opentofu/opentofu · error
Self reference: %s
Error message
Self reference: %s
What it means
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.
Source
Thrown at internal/dag/dag.go:145
// Look for cycles of more than 1 component
var err error
cycles := g.Cycles()
if len(cycles) > 0 {
for _, cycle := range cycles {
cycleStr := make([]string, len(cycle))
for j, vertex := range cycle {
cycleStr[j] = VertexName(vertex)
}
err = multierror.Append(err, fmt.Errorf(
"Cycle: %s", strings.Join(cycleStr, ", ")))
}
}
// Look for cycles to self
for _, e := range g.Edges() {
if e.Source() == e.Target() {
err = multierror.Append(err, fmt.Errorf(
"Self reference: %s", VertexName(e.Source())))
}
}
return err
}
// Cycles reports any cycles between graph nodes.
// Self-referencing nodes are not reported, and must be detected separately.
func (g *AcyclicGraph) Cycles() [][]Vertex {
var cycles [][]Vertex
for _, cycle := range StronglyConnected(&g.Graph) {
if len(cycle) > 1 {
cycles = append(cycles, cycle)
}
}
return cycles
}View on GitHub (pinned to 3561785c48)
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
Example fix
// before g.AddEdge(v, v) // after // (edge removed entirely, or corrected to the intended dependency) g.AddEdge(v, dep)
Defensive patterns
Strategy: validation
Validate before calling
for _, e := range g.Edges() {
if e.Source() == e.Target() {
return fmt.Errorf("self reference: %s", dag.VertexName(e.Source()))
}
} Prevention
- Filter self-edges in generators: skip AddEdge(v, v)
- Lint depends_on lists against the containing resource's own address
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- multiple roots: %#v
- no roots found
- Cycle: %s
- wrong number of operands (%d) for opResourceInstanceCurrentM
- wrong number of operands (%d) for opResourceInstanceDesired
AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15).
Data as JSON: /api/errors/aea9b0dd705ec904.
Report an issue: GitHub.