Last week, I attempted to delete a CloudFormation stack as part of cleaning up a test environment. The deletion started, but the stack got stuck in DELETE_FAILED status after 30 minutes. The stack remained in AWS and couldn’t be deleted through normal means, leaving me with orphaned resources and a lot of manual cleanup to do. In this post, I’ll walk through exactly what causes this and how to fix it.
The Problem
When you run aws cloudformation delete-stack --stack-name my-stack, CloudFormation attempts to delete all resources in the stack. If any resource fails to delete, the entire stack operation fails, and the stack enters DELETE_FAILED status. The stack persists, and subsequent delete attempts continue to fail.
The AWS console shows:
Stack DELETE_FAILED. The following resources [ResourceLogicalId] could not be deleted: [Error message].
Typical error messages include:
| Error Type | Description |
|---|---|
| Resource is not empty | S3 bucket contains objects, database contains backups |
| InvalidParameterValue | VPC has dependencies (ENIs, subnets still in use) |
| InvalidPermission.NotFound | IAM role lacks delete permissions |
| InvalidInstanceID.InUse | EC2 instance has termination protection or open connections |
| AccessDenied | The CloudFormation execution role lacks permissions |
Why Does This Happen?
- S3 bucket is not empty — CloudFormation can’t delete non-empty S3 buckets by design. This is a safety feature to prevent accidental data loss.
- VPC has lingering dependencies — A VPC can’t be deleted if it contains ENIs (Elastic Network Interfaces), instances, or subnets still in use by running services.
- Resource has Retention policy — The resource is configured with
DeletionPolicy: Retain, which tells CloudFormation to preserve it during stack deletion. - IAM permissions insufficient — The CloudFormation execution role doesn’t have permissions to delete the specific resource type.
- Resource has termination protection — EC2 instances, RDS databases, and other resources may have termination protection enabled, preventing deletion.
- Lambda function ENI cleanup delay — Lambda functions in VPCs leave behind ENIs that take time to clean up, blocking VPC deletion.
The Fix
Identify the resource causing the deletion failure and handle it appropriately.
First, check which resource failed:
# Describe the stack to see the DELETE_FAILED reason
aws cloudformation describe-stacks \
--stack-name my-stack \
--query "Stacks[0].StackStatusReason" \
--output text
Option 1: Empty S3 Bucket, Then Delete Stack
If the issue is an S3 bucket, empty it first:
# Remove all objects from the bucket
aws s3 rm s3://my-bucket --recursive
# Optionally, remove versioned objects and delete markers
aws s3api delete-objects \
--bucket my-bucket \
--delete "$(aws s3api list-object-versions \
--bucket my-bucket \
--query 'Versions[].{Key:Key,VersionId:VersionId}' \
--output json)"
# Now delete the stack
aws cloudformation delete-stack --stack-name my-stack
Option 2: Delete Stack While Retaining Specific Resources
If you want to preserve certain resources (like a database for backup purposes), delete the stack but retain them:
# Delete the stack but retain specific resources
aws cloudformation delete-stack \
--stack-name my-stack \
--retain-resources MyBucketLogicalId MyDatabaseLogicalId
Option 3: Manually Delete Blocking Resource, Then Retry
Identify and manually delete the blocking resource, then retry the stack deletion:
# Check which resources failed deletion
aws cloudformation describe-stack-events \
--stack-name my-stack \
--query "StackEvents[?ResourceStatus=='DELETE_FAILED']" \
--output table
# Manually delete the resource (example: delete an RDS database)
aws rds delete-db-instance \
--db-instance-identifier my-database \
--skip-final-snapshot
# Retry the stack deletion
aws cloudformation delete-stack --stack-name my-stack
How to Run This
- Identify the problematic resource using
describe-stacksordescribe-stack-events - If it’s an S3 bucket, empty it with
aws s3 rm --recursivebefore deleting the stack - For other resources, either disable termination protection or manually delete the resource first
- Retry the stack deletion with
delete-stack - Monitor deletion progress:
aws cloudformation describe-stacks --stack-name my-stack --query "Stacks[0].StackStatus"
Is This Safe?
Yes, but be cautious with --retain-resources. Resources you retain are no longer managed by CloudFormation and won’t be deleted. You must clean them up manually to avoid ongoing AWS charges.
Key Takeaway
CloudFormation deletion failures usually stem from non-empty S3 buckets, active dependencies, or insufficient permissions. Always empty S3 buckets before deleting stacks, handle resource dependencies explicitly, and use --retain-resources for anything you want to preserve beyond stack deletion.
Have questions or ran into a different CloudFormation issue? Connect with me on LinkedIn or X.