hashicorp/terraform · critical

Self reference: %s

Error message

Self reference: %s

What it means

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.

Source

Thrown at internal/dag/dag.go:247

					first = i
				}
			}

			// pivot the slice around our new first index
			if first > 0 {
				cycleStr = append(cycleStr[first:], cycleStr[:first]...)
			}

			err = errors.Join(err, fmt.Errorf(
				"Cycle:\n  %s", strings.Join(cycleStr, "\n  "),
			))
		}
	}

	// Look for cycles to self
	for _, e := range g.Edges() {
		if e.Source == e.Target {
			err = errors.Join(err, fmt.Errorf(
				"Self reference: %s", e.Source.Name()))
		}
	}

	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 c9def3e214)

Solutions

  1. 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).
  2. Run terraform graph and look for a node with an edge looping back to itself.
  3. If building the DAG programmatically, guard against adding Edge(v, v).
  4. Rename one of two colliding resources so the reference resolves to a distinct node.

Example fix

// before
resource "aws_instance" "web" {
  depends_on = [aws_instance.web] // self reference
}

// after — remove the self reference
resource "aws_instance" "web" {
  depends_on = [aws_instance.db]
}
Defensive patterns

Strategy: validation

Validate before calling

// Reject self-edges before validating/walking the graph
func hasSelfEdge(g *dag.AcyclicGraph) bool {
    for _, e := range g.Edges() {
        if e.Source == e.Target {
            return true
        }
    }
    return false
}

Type guard

func hasSelfEdge(g *dag.AcyclicGraph) bool {
    for _, e := range g.Edges() {
        if e.Source == e.Target {
            return true
        }
    }
    return false
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of hashicorp/terraform@c9def3e214 (2026-08-07). Data as JSON: /api/errors/ea7f34c430c6c0fa. Report an issue: GitHub.