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

  1. Locate the named vertex and delete the self edge (remove the self-referencing depends_on entry)
  2. In generator/transform code, filter e.Source() == e.Target() before calling AddEdge
  3. 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

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


AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15). Data as JSON: /api/errors/aea9b0dd705ec904. Report an issue: GitHub.