🎉 DevOps Interview Prep Bundle is live — 1000+ Q&A across 20 topicsGet it →
All Articles

Terraform Destroy Stuck on Dependency Violation: Fix in 5 Minutes

terraform destroy failing with 'DependencyViolation' or hanging on a resource that refuses to delete? Here is exactly how to diagnose orphaned dependencies, out-of-band changes, and deletion protection blocking a clean destroy.

Shubham4 min read
Share:Tweet

DependencyViolation errors happen because cloud providers enforce their own deletion ordering rules independently of what Terraform's dependency graph thinks it knows — usually because something was created outside Terraform, or a resource has a dependent that Terraform's state doesn't track.

Step 1: Read the Exact Error

bash
terraform destroy
 
# Error: deleting EC2 VPC (vpc-0abc123): DependencyViolation: The vpc
# 'vpc-0abc123' has dependencies and cannot be deleted.

AWS (or your cloud provider) is telling you the VPC still has something attached to it — Terraform's state doesn't necessarily know what, because the blocking resource might not be in Terraform's state at all.

Cause 1: A Resource Was Created Outside Terraform (Most Common)

bash
# Find everything actually inside the VPC, not just what Terraform manages
aws ec2 describe-network-interfaces --filters "Name=vpc-id,Values=vpc-0abc123" \
  --query 'NetworkInterfaces[*].[NetworkInterfaceId,Description,Status]' --output table

A manually-created ENI, a Lambda function with VPC config, or a load balancer created via the console (not Terraform) will block VPC deletion, and Terraform has no way to know about it or clean it up — it's not in the state file.

bash
# Common culprits: manually created security groups, an RDS instance
# someone spun up via console, a NAT gateway created outside Terraform
aws ec2 describe-security-groups --filters "Name=vpc-id,Values=vpc-0abc123"
aws elbv2 describe-load-balancers --query "LoadBalancers[?VpcId=='vpc-0abc123']"

Fix — manually delete the out-of-band resource, then retry destroy:

bash
aws elbv2 delete-load-balancer --load-balancer-arn arn:aws:elasticloadbalancing:...
terraform destroy    # Retry once the blocker is gone

Cause 2: Deletion Protection Enabled

bash
aws rds describe-db-instances --db-instance-identifier mydb \
  --query 'DBInstances[0].DeletionProtection'
# true    ← Terraform's destroy will fail here regardless of dependency graph correctness

Many resources (RDS instances, certain ALBs, some newer AWS resource types) support a deletion protection flag that blocks deletion at the API level, independent of Terraform entirely.

Fix — disable protection first, either via Terraform config change + apply, or directly:

hcl
resource "aws_db_instance" "main" {
  # ...
  deletion_protection = false    # Change this, apply, THEN destroy
}
bash
terraform apply    # Apply the protection change first
terraform destroy  # Then destroy will succeed

Cause 3: Resource Has an Implicit Dependent Terraform Doesn't Track

bash
# terraform state doesn't automatically know about implicit
# infrastructure relationships some providers create behind the scenes
terraform state list | grep vpc
# Shows the VPC and explicitly-managed subnets, but maybe not
# a NAT gateway's elastic IP association, VPC peering connections, etc.

Fix — import the untracked dependent resource into state so Terraform can manage its deletion too:

bash
aws ec2 describe-vpc-peering-connections --filters "Name=requester-vpc-info.vpc-id,Values=vpc-0abc123"
 
terraform import aws_vpc_peering_connection.orphaned pcx-0xyz789
terraform destroy    # Now Terraform knows to remove this too

Cause 4: Destroy Ordering Race — Cloud API Eventual Consistency

bash
terraform destroy
# Error: DependencyViolation ... (on a resource that SHOULD already be gone
# based on the plan output)

Some cloud APIs have eventual consistency delays — a security group deletion can report success while the underlying network interface detachment hasn't fully propagated yet, causing the next dependent deletion to fail transiently.

Fix — simply retry after a short wait; this is often not a real blocker, just a timing issue:

bash
sleep 30
terraform destroy

If it fails the same way repeatedly (not just once), it's not a timing issue — go back to Cause 1 or 3.

Cause 5: Terraform State Has a Stale Reference to an Already-Deleted Resource

bash
terraform destroy
# Error: reading EC2 Security Group (sg-0abc123): InvalidGroup.NotFound

Ironically, destroy can also fail because state references something that's already gone (deleted manually, or by a previous partial destroy).

Fix — remove the stale reference from state so Terraform stops trying to manage something that no longer exists:

bash
terraform state list | grep sg-0abc123
terraform state rm aws_security_group.orphaned
terraform destroy    # Retry, this resource is no longer in Terraform's plan

Diagnostic Approach for Any DependencyViolation

bash
# 1. Identify what the cloud provider says is blocking deletion (from the error)
# 2. Check if that specific thing is in Terraform's state
terraform state list | grep <resource-hint>
 
# 3. If NOT in state — it was created out-of-band, delete manually or import it
# 4. If IN state but destroy still fails — check for deletion protection flags
# 5. If nothing obvious — check for eventual-consistency timing, retry once

More Terraform troubleshooting? Read our Terraform plan unexpected destroy fix and Terraform apply hangs fix.

🔧

Today I Fixed

Short real fixes from production — posted daily

Browse fixes
Newsletter

Stay ahead of the curve

Get the latest DevOps, Kubernetes, AWS, and AI/ML guides delivered straight to your inbox. No spam — just practical engineering content.

Related Articles

Comments