Quick Answer
# Find what's blocking deletion
aws ec2 describe-network-interfaces \
--filters "Name=group-id,Values=sg-0abc1234" \
--query "NetworkInterfaces[].{ID:NetworkInterfaceId,Desc:Description}"
# Destroy in correct order
terraform destroy -target=aws_instance.web
terraform destroy
The Error
Error: deleting Security Group (sg-0abc1234):
DependencyViolation: resource sg-0abc1234 has a dependent object
Error: deleting VPC (vpc-0xyz5678):
DependencyViolation: The vpc 'vpc-0xyz5678' has dependencies and cannot be deleted.
Error: deleting Subnet (subnet-0def9012):
DependencyViolation: The subnet 'subnet-0def9012' has dependencies and cannot be deleted.
What Causes This
AWS won’t delete a resource that other resources depend on:
- VPC can’t be deleted with subnets, security groups, or endpoints still in it
- Security group can’t be deleted while attached to an EC2 instance, ENI, or RDS
- Subnet can’t be deleted with running instances or ENIs
- Out-of-band resources — something was created manually in the AWS console
Solution 1: Find Dependent Resources
Security Group Dependencies
# Find ENIs using this security group
aws ec2 describe-network-interfaces \
--filters "Name=group-id,Values=sg-0abc1234" \
--query "NetworkInterfaces[].{
ID:NetworkInterfaceId,
Type:InterfaceType,
Description:Description,
Status:Status,
AZ:AvailabilityZone
}" --output table
Common culprits:
- Lambda ENIs (can take 20+ minutes to auto-delete)
- ELB/ALB ENIs
- ECS task ENIs
- RDS interfaces
VPC Dependencies
# Find everything in the VPC
aws ec2 describe-instances --filters "Name=vpc-id,Values=vpc-0xyz5678" \
--query "Reservations[].Instances[].{ID:InstanceId,State:State.Name}"
aws ec2 describe-subnets --filters "Name=vpc-id,Values=vpc-0xyz5678" \
--query "Subnets[].SubnetId"
aws ec2 describe-security-groups --filters "Name=vpc-id,Values=vpc-0xyz5678" \
--query "SecurityGroups[].{ID:GroupId,Name:GroupName}"
aws ec2 describe-nat-gateways --filter "Name=vpc-id,Values=vpc-0xyz5678" \
--query "NatGateways[].{ID:NatGatewayId,State:State}"
aws ec2 describe-vpc-endpoints --filters "Name=vpc-id,Values=vpc-0xyz5678" \
--query "VpcEndpoints[].VpcEndpointId"
aws ec2 describe-internet-gateways \
--filters "Name=attachment.vpc-id,Values=vpc-0xyz5678" \
--query "InternetGateways[].InternetGatewayId"
Solution 2: Targeted Destroy (Inside Out)
Destroy child resources before parents:
# 1. Instances first
terraform destroy -target=aws_instance.web
terraform destroy -target=aws_instance.api
# 2. Then load balancers, NAT gateways
terraform destroy -target=aws_lb.main
terraform destroy -target=aws_nat_gateway.main
# 3. Then security groups, subnets
terraform destroy -target=aws_security_group.web
# 4. Then everything else
terraform destroy
Solution 3: create_before_destroy
For replacement (not destruction) — creates the new resource before deleting the old:
resource "aws_security_group" "web" {
name_prefix = "web-sg-"
vpc_id = aws_vpc.main.id
lifecycle {
create_before_destroy = true
}
}
Solution 4: Handle Lambda/ECS ENIs
Lambda and ECS create ENIs in your VPC that take 10-20 minutes to auto-delete after the function/service is destroyed:
# Check for lingering Lambda ENIs
aws ec2 describe-network-interfaces \
--filters "Name=group-id,Values=sg-0abc1234" \
"Name=status,Values=available" \
--query "NetworkInterfaces[].NetworkInterfaceId"
# Delete available (detached) ENIs
aws ec2 delete-network-interface --network-interface-id eni-0abc1234
# Then retry
terraform destroy
Solution 5: force_destroy for S3
S3 buckets can’t be deleted if they contain objects:
resource "aws_s3_bucket" "logs" {
bucket = "my-logs-bucket"
force_destroy = true # Deletes all objects on destroy
}
Solution 6: Remove from State (Last Resort)
If the resource was deleted manually:
# Resource already gone from AWS but still in state
terraform state rm aws_security_group.old_sg
# Then destroy the rest
terraform destroy
Common Dependency Chains
VPC
├── Internet Gateway (detach before delete)
├── NAT Gateway (delete, wait for ENI cleanup)
├── Subnets
│ ├── EC2 Instances
│ ├── RDS Instances
│ ├── ECS Tasks (ENIs)
│ ├── Lambda (ENIs)
│ └── ALB/NLB
├── Security Groups (delete after all ENIs detached)
├── VPC Endpoints
└── Route Tables
Terraform usually handles this order correctly. The error happens when out-of-band resources exist or when ENIs are slow to delete.
Hands-On Courses
- Terraform for Beginners on CopyPasteLearn
- Terraform By Example — practical code examples
Conclusion
Dependency violations mean something else is using the resource you’re deleting. Find the dependent resource with AWS CLI, destroy children before parents using -target, and wait for Lambda/ECS ENIs to auto-delete (10-20 minutes). Use force_destroy = true on S3 buckets and create_before_destroy for security group replacements.
