How to fix Error: Cycle: aws_security_group.sg_ping, aws_security_group.sg_8080 in Terraform

TerraformINTERMEDIATEHIGHUpdated Dec 30, 2025ยท 109 views

A circular dependency occurs when two or more AWS security groups reference each other in their ingress/egress rules. Terraform cannot determine creation order, causing the plan to fail. The fix is to separate security group rules into aws_security_group_rule resources.

Quick fix

Fixes Error: Cycle: aws_security_group.sg_ping, aws_security_group.sg_8080

resource "aws_security_group" "sg_ping" {
  name = "sg-ping"
  vpc_id = aws_vpc.main.id

  ingress {
    from_port       = 8080
    to_port         = 8080
    protocol        = "tcp"
    security_groups = [aws_security_group.sg_8080.id]
  }
}

resource "aws_security_group" "sg_8080" {
  name = "sg-8080"
  vpc_id = aws_vpc.main.id

  ingress {
    from_port       = 80
    to_port         = 80
    protocol        = "tcp"
    security_groups = [aws_security_group.sg_ping.id]
  }
}
  1. Move rules to aws_security_group_rule resources
  2. Create aws_security_group_rule resources for each rule
  3. Run terraform plan to verify the cycle is broken
  4. Apply the configuration
terraform โ€” error
resource "aws_security_group" "sg_ping" {
name = "sg-ping"
vpc_id = aws_vpc.main.id
ingress {
from_port = 8080
to_port = 8080
protocol = "tcp"
security_groups = [aws_security_group.sg_8080.id]
}
}
resource "aws_security_group" "sg_8080" {
name = "sg-8080"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
security_groups = [aws_security_group.sg_ping.id]
}
}
Error: Cycle: aws_security_group.sg_ping, aws_security_group.sg_8080

What this error means

Terraform builds a dependency graph to determine resource creation order. When security group A references security group B in its rules, and security group B references security group A, a circular dependency is created. AWS cannot create either group because each depends on the other already existing. This cycle is incompatible with Terraform's linear resource creation model.

Typical symptoms

  • terraform plan fails with 'Cycle: aws_security_group...' error
  • Error mentions multiple security group resources in a circular reference
  • Planning works with inline rules in security groups, but apply fails
  • Error appears when security groups reference each other's IDs in ingress/egress blocks

Common causes

  1. Inline ingress or egress rules within aws_security_group blocks that reference other security group IDs
  2. Two or more security groups configured to allow traffic from each other simultaneously
  3. Direct references between security group resources using source_security_group_id

How to fix "Error: Cycle: aws_security_group.sg_ping, aws_security_group.sg_8080"

1Move rules to aws_security_group_rule resources

Remove all ingress/egress rules from your aws_security_group blocks. Create separate aws_security_group_rule resources for each rule instead.

Before (causes cycle):

hcl
resource "aws_security_group" "sg_ping" {
  name = "sg-ping"
  vpc_id = aws_vpc.main.id

  ingress {
    from_port       = 8080
    to_port         = 8080
    protocol        = "tcp"
    security_groups = [aws_security_group.sg_8080.id]
  }
}

resource "aws_security_group" "sg_8080" {
  name = "sg-8080"
  vpc_id = aws_vpc.main.id

  ingress {
    from_port       = 80
    to_port         = 80
    protocol        = "tcp"
    security_groups = [aws_security_group.sg_ping.id]
  }
}

After (breaks cycle):

hcl
resource "aws_security_group" "sg_ping" {
  name   = "sg-ping"
  vpc_id = aws_vpc.main.id
}

resource "aws_security_group" "sg_8080" {
  name   = "sg-8080"
  vpc_id = aws_vpc.main.id
}
2Create aws_security_group_rule resources for each rule

Define rules separately after the security groups. This forces Terraform to create both groups first, then apply rules afterward.

hcl
resource "aws_security_group_rule" "sg_ping_from_8080" {
  type                     = "ingress"
  from_port                = 80
  to_port                  = 80
  protocol                 = "tcp"
  security_group_id        = aws_security_group.sg_ping.id
  source_security_group_id = aws_security_group.sg_8080.id
}

resource "aws_security_group_rule" "sg_8080_from_ping" {
  type                     = "ingress"
  from_port                = 8080
  to_port                  = 8080
  protocol                 = "tcp"
  security_group_id        = aws_security_group.sg_8080.id
  source_security_group_id = aws_security_group.sg_ping.id
}
3Run terraform plan to verify the cycle is broken

Execute terraform plan to confirm Terraform can now calculate a valid resource creation order without cycles.

bash
terraform plan

You should see all resources scheduled to be created without cycle errors.

4Apply the configuration

Once the plan looks correct, apply the changes:

bash
terraform apply

Terraform will first create both security groups, then create the rules to allow traffic between them.

Advanced notes

Why aws_security_group_rule works:
aws_security_group_rule resources are applied in a separate phase after aws_security_group resources. This gives Terraform a clear dependency order: (1) Create empty security groups, (2) Create rules that reference those groups.

Detecting cycles in large configs:
Use terraform graph to visualize your dependency tree and spot cycles:

bash
terraform graph | grep -A5 -B5 "security_group"

Alternative: depends_on (not recommended):
While you can use depends_on to force ordering, this only works if there's no actual circular reference. True cycles cannot be resolved with depends_on.

Refactoring existing code:
If migrating from inline rules to aws_security_group_rule, Terraform will plan to destroy and recreate security groups. To avoid downtime, use state manipulation or apply in stages.

Frequently asked questions

What does "Error: Cycle: aws_security_group.sg_ping, aws_security_group.sg_8080" mean?
Terraform builds a dependency graph to determine resource creation order. When security group A references security group B in its rules, and security group B references security group A, a circular dependency is created. AWS cannot create either group because each depends on the other already existing.
How do I fix "Error: Cycle: aws_security_group.sg_ping, aws_security_group.sg_8080"?
A circular dependency occurs when two or more AWS security groups reference each other in their ingress/egress rules. Terraform cannot determine creation order, causing the plan to fail. The fix is to separate security group rules into aws_security_group_rule resources.
What causes "Error: Cycle: aws_security_group.sg_ping, aws_security_group.sg_8080"?
Inline ingress or egress rules within aws_security_group blocks that reference other security group IDs Two or more security groups configured to allow traffic from each other simultaneously Direct references between security group resources using source_security_group_id
Is the "Error: Cycle: aws_security_group.sg_ping, aws_security_group.sg_8080" error serious?
Yes. This is a high-severity error that usually blocks work until it is fixed, but the steps above resolve it.

Official resources & further reading