CloudFormation Error Guide: 'Circular dependency between resources' — Break the Reference Cycle
Fix CloudFormation 'Circular dependency between resources' by breaking Ref and GetAtt cycles with standalone association resources and careful DependsOn.
- #iac
- #infrastructure-as-code
- #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
Before provisioning, CloudFormation builds a dependency graph from every Ref, Fn::GetAtt, and DependsOn, then topologically sorts it to pick a creation order. If the graph contains a cycle, no valid order exists and the stack fails at validation:
Circular dependency between resources: [InstanceSecurityGroup, DatabaseSecurityGroup, InstanceSecurityGroupIngress]
The bracketed list is the set of resources CloudFormation could not order because each depends, directly or transitively, on another in the set.
Symptoms
create-stack/update-stackfails almost immediately withCircular dependency between resources: [...].- No resources are created (or the update rolls back) because validation happens before provisioning.
- The named resources reference each other through
Ref/GetAtt, often two security groups or a resource and its own association. - Adding a
DependsOnto “fix” ordering made it worse.
Common Root Causes
- Mutual security-group references — SG-A allows ingress from SG-B while SG-B allows ingress from SG-A, each inlined in the group’s own
SecurityGroupIngress. - Resource ↔ association cycle — a resource references an association that references the resource (route tables, gateway attachments, target group registrations).
DependsOnfighting an implicitRef— a manualDependsOnpointing back at something that alreadyRefs this resource.- Outputs/inputs looping through nested stacks — a child output feeds a parent value that feeds the child.
- IAM role ↔ resource — a role that references a resource ARN whose policy references the role.
Diagnostic Workflow
Validate the template locally to get the exact cycle members fast:
aws cloudformation validate-template --template-body file://template.yaml
Lint for dependency issues, which flags many cycles with line numbers:
cfn-lint template.yaml
Extract every dependency edge so you can see the loop:
# list all Ref / GetAtt / DependsOn usages
grep -nE 'Ref|Fn::GetAtt|GetAtt|DependsOn' template.yaml
For each resource named in the error, write down what it references and what references it; the cycle is where those two lists overlap. Render the graph if the template is large:
cfn-flip template.yaml template.json # normalize, then inspect programmatically
Example Root Cause Analysis
A template defined two security groups. InstanceSecurityGroup had an inline SecurityGroupIngress referencing DatabaseSecurityGroup, and DatabaseSecurityGroup had an inline ingress referencing InstanceSecurityGroup. Each group needed the other to exist first to resolve the Ref, so CloudFormation reported Circular dependency between resources: [InstanceSecurityGroup, DatabaseSecurityGroup].
The fix was to remove the mutual inline ingress rules and express the relationship with standalone AWS::EC2::SecurityGroupIngress resources. A standalone ingress resource can reference both groups by GroupId and SourceSecurityGroupId after both groups are created, so the two groups no longer depend on each other — they each depend only on nothing, and the two ingress resources depend on both groups. The cycle became a valid DAG and the stack deployed.
Prevention Best Practices
- Express bidirectional relationships (SG-to-SG ingress, associations) as standalone resources, not inline in the resources they connect.
- Avoid inline
SecurityGroupIngress/Egressbetween two groups; use separateAWS::EC2::SecurityGroupIngressresources. - Add
DependsOnonly to add ordering, never to resolve a data dependency thatRefalready implies. - Run
cfn-lintin CI to catch cycles before deploy. - Keep nested-stack outputs one-directional; do not feed a child output back into that child.
Quick Command Reference
aws cloudformation validate-template --template-body file://template.yaml
cfn-lint template.yaml
grep -nE 'Ref|Fn::GetAtt|DependsOn' template.yaml
cfn-flip template.yaml template.json
Conclusion
A circular dependency means CloudFormation’s resource graph has no valid creation order because two or more resources reference each other. The durable fix is structural: break the mutual reference by pulling the relationship into a standalone resource (typically a separate ingress or association) that depends on both endpoints instead of making the endpoints depend on each other. Validate and lint in CI so cycles are caught before they ever reach a deploy.
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.