Fixing the Terraform 'Instance cannot be destroyed' Error

intermediate🏗️ Terraform2026-06-25| Terraform CLI (All versions), AWS/Azure/GCP Providers, Linux/macOS/Windows

Error Message

Error: Instance cannot be destroyed Resource aws_s3_bucket.example has lifecycle.prevent_destroy set, but the plan calls for this resource to be destroyed. To avoid this error and continue, you must remove the lifecycle.prevent_destroy configuration from this resource.
#terraform#devops#aws#infrastructure-as-code#troubleshooting

The ProblemYou’re mid-deployment when the terminal suddenly hits a brick wall. Instead of the usual progress bar, you're staring at a red error message: Instance cannot be destroyed. This isn't a bug in Terraform. It's a safety feature doing exactly what it was told to do. Usually, a developer added a guardrail to a high-stakes resource—like a production RDS database or a core VPC—to prevent someone from accidentally deleting it with a stray command.

The Error Message```

Error: Instance cannot be destroyed

Resource aws_s3_bucket.example has lifecycle.prevent_destroy set, but the plan calls for this resource to be destroyed. To avoid this error and continue, you must remove the lifecycle.prevent_destroy configuration from this resource.


## Why did this trigger?The `prevent_destroy` meta-argument is the ultimate safety catch. When set to `true`, Terraform will reject any plan that results in that resource being deleted. This protection usually triggers in two specific scenarios:
- **Intentional Deletion:** You ran `terraform destroy` or deleted the resource block from your `.tf` files.- **Accidental Replacement:** You changed a setting that requires a "Force New" action. For example, changing the `name` of an `aws_s3_bucket` or the `availability_zone` of an `aws_instance` forces Terraform to delete the old resource and create a new one.## The Quick Fix: Temporarily Disabling ProtectionIf you actually need to replace or delete the resource, you have to modify the code. Terraform does not provide a command-line flag (like `--force`) to bypass this safety check. You must manually toggle the protection off.
- Open the configuration file containing the resource.- Locate the `lifecycle` block.- Set `prevent_destroy = false` or comment out the entire block.```
resource "aws_s3_bucket" "example" {
  bucket = "my-production-data-12345"

  # lifecycle {
  #   prevent_destroy = true
  # }
}

Once you save the file, run terraform plan again. The error will disappear, and Terraform will proceed with the destruction or replacement as requested.

The Permanent Fix: Handling Resource ReplacementsWhat if you didn't want to delete anything? Often, this error pops up during a routine terraform apply because of a subtle configuration change. If a replacement is being forced unexpectedly, you need to investigate the cause.

Step 1: Analyze the PlanRun terraform plan and search for the phrase # aws_s3_bucket.example must be replaced. Terraform will mark the specific attribute causing the conflict with # forces replacement. If you see that changing a simple tag or a description is forcing a replacement, it might be a provider-specific quirk.

Step 2: Revert or MigrateIf the replacement was a mistake, revert your .tf file to its previous state. If the change is mandatory but you cannot afford to lose the resource, consider using a moved block (available in Terraform 1.1+). This allows you to rename resources in the state file without recreating the actual infrastructure.

Step 3: Removing from State (Advanced)Sometimes you want to keep the resource in the real world (e.g., in the AWS Console) but stop managing it via Terraform. In this case, use the state rm command:

terraform state rm aws_s3_bucket.example

This command deletes the resource from your terraform.tfstate file. You can then safely remove the code block without Terraform attempting to touch the actual S3 bucket.

Best Practices for ProductionUsing prevent_destroy is a smart move for stateful resources like databases or storage. However, applying it to every single resource can make your CI/CD pipelines brittle and frustrating to manage. Reserve it for the "crown jewels" of your infrastructure.

Configuration errors often stem from malformed data in external files. If your Terraform variables are fed from complex JSON or YAML sources, a single indentation error can trigger an unwanted resource replacement. I use the YAML ↔ JSON Converter on ToolCraft to validate my config structures. It helps me catch syntax errors before they ever reach the Terraform CLI.

Verification StepsTo confirm the fix is solid, follow this workflow:

  • Run terraform plan -out=tfplan.- Confirm the plan finishes without the "Instance cannot be destroyed" error.- Carefully review the output to ensure only the intended 5 or 10 resources are being touched.- Execute terraform apply tfplan to commit the changes.Once the update is complete, don't forget to set prevent_destroy = true back to true. It's better to have the protection and not need it than to lose a production database to a typo.

Related Error Notes