OpenTofu Error: 'Cycle' — Cause, Fix, and Troubleshooting Guide
Fix OpenTofu 'Error: Cycle' dependency loops from circular resource references, mutual module dependencies, and depends_on chains.
- #opentofu
- #iac
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
OpenTofu builds a directed acyclic graph of your resources and evaluates it in dependency order. If two or more resources depend on each other — directly or through a chain — there is no valid order, so OpenTofu reports a cycle:
Error: Cycle: aws_security_group.app, aws_security_group.db
A longer form lists every node in the loop:
Error: Cycle: aws_security_group_rule.app_to_db,
aws_security_group.db, aws_security_group_rule.db_to_app,
aws_security_group.app
Symptoms
tofu plan/applyfails withError: Cycle:followed by a comma-separated list of resource addresses.- The listed resources reference each other, forming a loop.
- Common with security groups that reference each other, or modules that consume each other’s outputs.
- Adding a
depends_onsometimes triggers it where there was none before.
Common Root Causes
- Mutual security-group references — group A allows B and group B allows A via inline rules.
- Circular module dependencies — module X uses an output of Y, and Y uses an output of X.
- depends_on loops — explicit dependencies that point back at an ancestor.
- Self-referential attributes — a resource referencing its own computed value.
- Over-broad
depends_onon a whole module pulling in a resource that depends back.
How to diagnose
Read the cycle members — the fix is almost always to break one edge:
tofu plan 2>&1 | sed -n '1,10p'
Visualize the dependency graph to see the loop:
tofu graph | dot -Tsvg > graph.svg
tofu graph | grep -i security_group
Trace which attribute creates each edge in the loop:
grep -rn 'aws_security_group\.' *.tf
Fixes
Break mutual security-group references by moving the rules into standalone aws_security_group_rule (or vpc_security_group_ingress_rule) resources instead of inline blocks:
resource "aws_security_group" "app" {}
resource "aws_security_group" "db" {}
resource "aws_vpc_security_group_ingress_rule" "app_to_db" {
security_group_id = aws_security_group.db.id
referenced_security_group_id = aws_security_group.app.id
ip_protocol = "tcp"
from_port = 5432
to_port = 5432
}
Standalone rule resources depend on the groups, but the groups no longer depend on each other — the cycle disappears.
Break circular module dependencies by extracting the shared resource into a third module both consume, so the arrows point one way.
Remove unnecessary depends_on — most dependencies are inferred from references; explicit depends_on back at an ancestor creates loops.
What to watch out for
- Prefer standalone rule resources over inline
ingress/egressblocks whenever two groups reference each other. depends_onshould point forward to things a resource genuinely needs; never at something downstream of it.- Refactor bidirectional module coupling into a shared lower-level module rather than passing outputs both ways.
tofu graph | dotis the fastest way to see the loop when the address list is long.
Related
- OpenTofu Error: ‘Reference to undeclared resource’ — Cause, Fix, and Troubleshooting Guide
- OpenTofu Error: ‘Duplicate resource configuration’ — Cause, Fix, and Troubleshooting Guide
- OpenTofu Error: ‘Invalid count argument’ — Cause, Fix, and Troubleshooting Guide
Get 500 Battle-Tested DevOps AI Prompts — Free
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.