hashicorp/terraform · error

Self reference

Error message

Self reference: %s

What it means

Returned by AcyclicGraph.Validate when an edge has the same Source and Target — a self-loop. Unlike multi-vertex cycles (handled by [857]), self-loops are detected by a separate scan after the SCC pass because StronglyConnected excludes single-vertex trivial components. Each self-referencing vertex is reported by name.

Solutions

  1. Find the resource named in the error and remove the self-reference in its depends_on (or equivalent dependency declaration).
  2. If generated by a template, fix the template so it does not emit a resource's own address as a dependency.
  3. For internal graph builders, guard edge insertion against Source == Target.
  4. Re-run 'terraform plan' to confirm the self-reference is resolved.

Example fix

// before
resource "a" "x" {
  depends_on = [a.x]
}

// after
resource "a" "x" {}
Defensive patterns

Strategy: validation

Validate before calling

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

Type guard

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

Prevention

When it happens

Trigger: A graph edge whose Source and Target are the same Vertex is added (graph.Connect or Dagger edge insertion), then AcyclicGraph.Validate() is called. In Terraform this typically means a resource somehow lists itself in depends_on or an internal transformer wires a node to itself.

Common situations: Generated configs that include a resource in their own depends_on (often via templating that interpolates the resource's own address); internal graph transformers with off-by-one bugs wiring a node to itself; module self-includes.

Related errors


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

Appendix: 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 d32a084675)