AWS Error Guide: 'DependencyViolation' — Delete Blocked by Attached Resources
Fix the AWS DependencyViolation error when deleting VPCs, subnets, security groups, and internet gateways: find the ENIs, references, and attachments still holding the resource.
- #aws
- #cloud
- #troubleshooting
- #errors
Stuck on this AWS with AI error? Get the free incident triage checklist
A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.
Overview
DependencyViolation is EC2’s way of saying “you cannot delete this network resource because something is still using it.” AWS enforces referential integrity across VPC resources: a subnet cannot be deleted while an ENI lives in it, a security group cannot be deleted while another rule or ENI references it, and an internet gateway cannot be detached while public IPs still route through it. The delete call is rejected with HTTP 400 rather than cascading.
It surfaces from the CLI, an SDK, or Terraform:
An error occurred (DependencyViolation) when calling the DeleteSubnet operation: The subnet 'subnet-REDACTED' has dependencies and cannot be deleted.
The security-group and internet-gateway variants read similarly:
An error occurred (DependencyViolation) when calling the DeleteSecurityGroup operation: resource sg-REDACTED has a dependent object
An error occurred (DependencyViolation) when calling the DetachInternetGateway operation: Network vpc-REDACTED has some mapped public address(es). Please unmap those public address(es) before detaching the gateway.
It occurs whenever you try to tear down VPC infrastructure — or run terraform destroy — while a lingering elastic network interface, security-group reference, NAT gateway, or load balancer still holds the resource.
Symptoms
DeleteSubnet,DeleteSecurityGroup,DeleteVpc,DeleteRouteTable, orDetachInternetGatewayfails withDependencyViolation.terraform destroystalls or errors on a VPC/subnet/security-group resource while other resources destroy cleanly.- Deletions succeed in dev but fail in an environment that also has load balancers, RDS, Lambda-in-VPC, or VPC endpoints.
- The resource “looks empty” in the console but still cannot be removed.
aws ec2 delete-subnet --subnet-id subnet-REDACTED
An error occurred (DependencyViolation) when calling the DeleteSubnet operation: The subnet 'subnet-REDACTED' has dependencies and cannot be deleted.
Common Root Causes
1. A lingering elastic network interface (ENI) in the subnet
The most common cause. A NAT gateway, VPC endpoint, RDS instance, Lambda-in-VPC, or a load balancer created an ENI that still occupies the subnet.
aws ec2 describe-network-interfaces \
--filters "Name=subnet-id,Values=subnet-REDACTED" \
--query 'NetworkInterfaces[].[NetworkInterfaceId,InterfaceType,Description,Status]' \
--output table
-------------------------------------------------------------------------
| eni-REDACTED | nat_gateway | Interface for NAT Gateway nat-REDACTED |
| eni-REDACTED | vpc_endpoint | VPC Endpoint Interface vpce-REDACTED |
-------------------------------------------------------------------------
The InterfaceType and Description tell you which AWS service owns the ENI — delete that service resource, not the ENI directly.
2. A security group referenced by another security group or ENI
A security group cannot be deleted while an ENI uses it, or while another SG’s rule references it as a source/destination.
aws ec2 describe-network-interfaces \
--filters "Name=group-id,Values=sg-REDACTED" \
--query 'NetworkInterfaces[].NetworkInterfaceId' --output text
aws ec2 describe-security-groups \
--query "SecurityGroups[?IpPermissions[?UserIdGroupPairs[?GroupId=='sg-REDACTED']]].GroupId" \
--output text
The first shows ENIs still attached; the second shows other security groups whose rules reference it.
3. Public IPs / EIPs still mapped when detaching an internet gateway
DetachInternetGateway fails while any instance or ENI in the VPC still has a mapped public IPv4 address or associated Elastic IP.
aws ec2 describe-instances \
--filters "Name=vpc-id,Values=vpc-REDACTED" \
--query 'Reservations[].Instances[?PublicIpAddress].[InstanceId,PublicIpAddress]' \
--output text
4. Route tables, NAT gateways, or endpoints still in the VPC
DeleteVpc fails while dependent subnets, route tables (non-main), NAT gateways, VPC endpoints, or peering connections remain.
aws ec2 describe-nat-gateways --filter "Name=vpc-id,Values=vpc-REDACTED" \
--query 'NatGateways[?State!=`deleted`].[NatGatewayId,State]' --output text
aws ec2 describe-vpc-endpoints --filters "Name=vpc-id,Values=vpc-REDACTED" \
--query 'VpcEndpoints[].VpcEndpointId' --output text
5. A load balancer or RDS subnet group still bound to the subnet
ELBv2 nodes and RDS subnet groups pin ENIs into subnets and often outlive the Terraform module that “should” have removed them.
aws elbv2 describe-load-balancers \
--query "LoadBalancers[?VpcId=='vpc-REDACTED'].[LoadBalancerName,LoadBalancerArn]" \
--output text
Diagnostic Workflow
Step 1: Identify exactly which resource and operation failed
aws ec2 delete-subnet --subnet-id subnet-REDACTED 2>&1 | grep -oE 'Delete[A-Za-z]+|Detach[A-Za-z]+'
Note whether it is a subnet, security group, VPC, route table, or internet gateway — each has a different dependency set.
Step 2: For a subnet, enumerate the ENIs holding it
aws ec2 describe-network-interfaces \
--filters "Name=subnet-id,Values=subnet-REDACTED" \
--query 'NetworkInterfaces[].[NetworkInterfaceId,InterfaceType,Description,Status,Attachment.InstanceId]' \
--output table
The InterfaceType (nat_gateway, vpc_endpoint, lambda, interface, network_load_balancer) names the owning service.
Step 3: For a security group, find both ENIs and rule references
aws ec2 describe-network-interfaces \
--filters "Name=group-id,Values=sg-REDACTED" \
--query 'NetworkInterfaces[].[NetworkInterfaceId,Description]' --output table
aws ec2 describe-security-groups \
--query "SecurityGroups[?IpPermissions[?UserIdGroupPairs[?GroupId=='sg-REDACTED']] || IpPermissionsEgress[?UserIdGroupPairs[?GroupId=='sg-REDACTED']]].[GroupId,GroupName]" \
--output table
Step 4: For a VPC, list every category of remaining child resource
for kind in subnets route-tables nat-gateways vpc-endpoints vpc-peering-connections internet-gateways; do
echo "== $kind =="
aws ec2 describe-$kind --filters "Name=vpc-id,Values=vpc-REDACTED" 2>/dev/null \
--query 'length(@)' 2>/dev/null
done
Step 5: Delete owning service resources in dependency order
Remove the service that created the ENI (NAT gateway, endpoint, load balancer, RDS), wait for it to finish, then retry the network delete:
aws ec2 delete-nat-gateway --nat-gateway-id nat-REDACTED
aws ec2 wait nat-gateway-deleted --nat-gateway-ids nat-REDACTED
aws ec2 delete-subnet --subnet-id subnet-REDACTED
Example Root Cause Analysis
A terraform destroy on a networking module failed on aws_subnet.private[0] with DependencyViolation. The subnet appeared empty in the console, so the operator assumed a stuck API.
Listing ENIs told the real story:
aws ec2 describe-network-interfaces \
--filters "Name=subnet-id,Values=subnet-REDACTED" \
--query 'NetworkInterfaces[].[InterfaceType,Description]' --output text
nat_gateway Interface for NAT Gateway nat-REDACTED
A NAT gateway defined in a different Terraform module (a shared-egress stack) still had its ENI in this subnet. Because the two modules were destroyed independently, Terraform had no dependency edge between them, so it tried to delete the subnet while the NAT gateway lived on.
Fix: delete the NAT gateway first, wait for nat-gateway-deleted, then re-run the destroy:
aws ec2 delete-nat-gateway --nat-gateway-id nat-REDACTED
aws ec2 wait nat-gateway-deleted --nat-gateway-ids nat-REDACTED
terraform destroy -target=aws_subnet.private
The subnet deleted cleanly. The lasting fix was to add an explicit dependency (moving the NAT gateway into the same module, or a depends_on) so ordering is enforced on every teardown.
Prevention Best Practices
- Tear down in dependency order: service resources (NAT gateways, endpoints, load balancers, RDS, Lambda-in-VPC) first, then subnets/route tables, then the internet gateway and VPC.
- Always
aws ec2 waitfor NAT gateways and endpoints to reach a deleted state before deleting their subnet — deletion is asynchronous and leaves ENIs briefly. - In Terraform, keep VPC child resources in the same module (or use explicit
depends_on) so destroy ordering is derived automatically, not left to chance. - Before deleting a security group, migrate ENIs off it and remove cross-references from other groups’ rules.
- Detach EIPs and disable auto-assign public IPs before detaching an internet gateway.
- When teardown stalls, list ENIs by
subnet-id/group-idfirst — theInterfaceType/Descriptionfield names the owning service every time.
Quick Command Reference
# Which ENIs hold a subnet (and what created them)
aws ec2 describe-network-interfaces --filters "Name=subnet-id,Values=subnet-REDACTED" \
--query 'NetworkInterfaces[].[NetworkInterfaceId,InterfaceType,Description]' --output table
# ENIs and rule references holding a security group
aws ec2 describe-network-interfaces --filters "Name=group-id,Values=sg-REDACTED" \
--query 'NetworkInterfaces[].NetworkInterfaceId' --output text
aws ec2 describe-security-groups \
--query "SecurityGroups[?IpPermissions[?UserIdGroupPairs[?GroupId=='sg-REDACTED']]].GroupId" --output text
# Remaining VPC children before DeleteVpc
aws ec2 describe-nat-gateways --filter "Name=vpc-id,Values=vpc-REDACTED" \
--query 'NatGateways[?State!=`deleted`].NatGatewayId' --output text
aws ec2 describe-vpc-endpoints --filters "Name=vpc-id,Values=vpc-REDACTED" \
--query 'VpcEndpoints[].VpcEndpointId' --output text
# Delete a NAT gateway and wait before deleting its subnet
aws ec2 delete-nat-gateway --nat-gateway-id nat-REDACTED
aws ec2 wait nat-gateway-deleted --nat-gateway-ids nat-REDACTED
Conclusion
DependencyViolation means a VPC resource still has something referencing it. The usual root causes:
- A lingering ENI from a NAT gateway, VPC endpoint, Lambda-in-VPC, RDS, or load balancer occupying the subnet.
- A security group still attached to an ENI or referenced by another group’s rule.
- Mapped public IPs / EIPs blocking an internet-gateway detach.
- Route tables, NAT gateways, endpoints, or peering connections still inside the VPC.
- A load balancer or RDS subnet group pinning ENIs into the subnet.
List the ENIs and references first — the InterfaceType/Description tells you which service to delete — then tear down in dependency order and wait for async deletes to finish. The error is integrity protection, not a bug: remove the dependent, then the delete succeeds.
Fixed it? Get 500 AWS with AI & 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.
Did this fix your issue?
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.