The prevent_destroy lifecycle argument protects critical resources from accidental deletion. When enabled, Terraform blocks any destroy operations. To proceed, you must either remove the protect_destroy setting, delete the resource from configuration, or remove it from Terraform state.
Terraform's lifecycle.prevent_destroy is a safeguard that prevents resources from being destroyed as part of a terraform destroy or terraform apply operation. When this protection is enabled and Terraform attempts to destroy the resource, it will fail with an error. This is intentional protection for critical resources like production databases, storage buckets with important data, or compliance-sensitive assets. However, it creates a deliberate blocker when you actually need to destroy the resource. The error occurs because Terraform evaluates the prevent_destroy setting early in its planning phase, before any execution. This means the protection applies regardless of whether you're intentionally destroying the resource or accidentally did so by removing its configuration.
First, identify which resource has prevent_destroy enabled and confirm it's actually set to true.
# Look for this pattern in your Terraform configuration
resource "aws_instance" "example" {
# ... configuration ...
lifecycle {
prevent_destroy = true
}
}If you see this in your code, this is the cause. Note the resource type and name for the next steps.
If you genuinely want to destroy this resource, set prevent_destroy to false or remove the lifecycle block entirely.
# Option 1: Change to false
resource "aws_instance" "example" {
# ... configuration ...
lifecycle {
prevent_destroy = false
}
}
# Option 2: Remove the lifecycle block entirely
resource "aws_instance" "example" {
# ... configuration ...
}After making this change, run terraform plan to verify the change is recognized:
terraform planThen you can proceed with destroy:
terraform apply # Apply the plan that now allows destruction
terraform destroy # Or destroy specific resourceIf you want to unmanage the resource (stop Terraform from tracking it) without actually destroying it in your cloud provider, use terraform state rm:
terraform state rm aws_instance.exampleThis removes the resource from Terraform's state file, but the actual infrastructure remains running in AWS (or your provider). This is useful when:
- You want to manage the resource outside of Terraform
- You're migrating the resource to a different Terraform configuration
- You want to keep the resource but stop protecting it
Verify the resource was removed from state:
terraform state list | grep exampleThe resource should no longer appear in the state.
If the protected resource is in a nested module and you cannot edit the module directly, you have limited options:
1. Request the module owner/maintainer to add a variable to make prevent_destroy configurable:
variable "prevent_destroy" {
type = bool
default = true
}
lifecycle {
prevent_destroy = var.prevent_destroy
}2. Fork/copy the module and customize it for your use case
3. Use terraform state rm to remove the module's resources from state before destroying the parent module:
terraform state rm 'module.my_module.aws_instance.example'4. As a last resort, manually delete the infrastructure outside Terraform, then clean up state:
# Manually delete in cloud console, then
terraform state rm <resource_address>Understanding prevent_destroy Behavior:
prevent_destroy only blocks destruction when the resource block remains in configuration. If you remove the resource block entirely from your .tf files, Terraform will allow destruction because the lifecycle rule is removed along with the resource definition. This is a common gotcha when managing resources.
When prevent_destroy Should Be Used:
- Production databases with critical data
- S3 buckets storing important backups or archives
- RDS instances serving live applications
- Compliance-critical assets subject to regulations
- Any stateful infrastructure that cannot be easily replaced
Alternative Approaches to Prevent Accidental Destruction:
1. Use Terraform Cloud with mandatory approval policies for destroy operations
2. Implement Cost Estimation gates that flag destruction of expensive resources
3. Use separate Terraform workspaces for production to add a layer of separation
4. Implement a tag-based policy in your cloud provider to block deletion of tagged resources
5. Use terraform lock files and code review processes to prevent sneaky removals
Removing prevent_destroy vs. Removing Resource from State:
- Set prevent_destroy = false then destroy: Completely removes the resource from your cloud provider
- terraform state rm: Removes Terraform tracking but leaves the actual infrastructure running in the cloud
- Choose based on whether you want the cloud resources to exist after being unmanaged
Error: Error installing helm release: cannot re-use a name that is still in use
How to fix "release name in use" error in Terraform with Helm
Error: Error creating GKE Cluster: BadRequest
BadRequest error creating GKE cluster in Terraform
Error: External program failed to produce valid JSON
External program failed to produce valid JSON
Error: Unsupported argument in child module call
How to fix "Unsupported argument in child module call" in Terraform
Error: network is unreachable
How to fix "network is unreachable" in Terraform