Pulumi Error: 'resource cannot be deleted because it is protected' — Cause, Fix, and Troubleshooting Guide
Fix Pulumi 'cannot be deleted because it is protected. Set the protect resource option to false to delete this resource' — safely clear protect and delete.
- #pulumi
- #iac
- #troubleshooting
- #errors
Fixing errors like this? Get 500 free DevOps AI prompts
500 copy-paste AI prompts for the stack you actually run — one PDF, free.
Overview
error: resource '...' cannot be deleted because it is protected means the resource has
the protect resource option set to true, and your operation would delete or replace
it. Protection is a deliberate guardrail: it stops pulumi destroy, a code removal, or a
replacement from tearing down critical infrastructure (databases, buckets with data, DNS
zones) by accident.
Pulumi will not override protection automatically. You must explicitly clear the flag —
either in code or with pulumi state unprotect — before the delete or replace can proceed.
error: resource 'urn:pulumi:prod::app::aws:s3/bucket:Bucket::data' cannot be deleted
because it is protected. Set the 'protect' resource option to 'false' to delete this resource
Symptoms
pulumi destroyaborts and lists one or more protected resources it refuses to delete.pulumi upfails when a change would replace a protected resource (a replacement is a delete + create).- Removing a resource from your program and running
pulumi uperrors instead of deleting it. - The message always names the resource by its full URN and tells you to set
protecttofalse.
Common Root Causes
1. The resource was explicitly protected in code
Someone set the protect resource option to guard the resource:
const data = new aws.s3.Bucket("data", {
bucket: "prod-data",
}, { protect: true });
While that option is present and true, any delete or replace of data is blocked.
2. Protection was set via pulumi state protect
protect can be toggled directly on the state without touching code, so the source program
may look “clean” while the state still marks the resource protected.
3. A change forces a replacement of a protected resource
Even if you are not deleting the resource on purpose, editing an immutable property (which requires replace) triggers a delete step — and that step is blocked by protection.
~ aws:s3/bucket:Bucket data replace [diff: bucket]
error: ... cannot be deleted because it is protected ...
4. retainOnDelete vs protect confusion
retainOnDelete leaves the cloud object behind but removes it from state; protect blocks
the operation entirely. Reaching for the wrong one is a common source of surprise here.
How to Diagnose
See exactly which resources are protected in the current stack:
pulumi stack --show-urns
Inspect a single resource’s state, including its protect flag, by exporting the stack:
pulumi stack export | jq '.deployment.resources[]
| select(.protect == true)
| {urn, type}'
Preview the operation to confirm whether it is a delete or a replacement that is blocked:
pulumi preview --diff
Fixes
Clear protection in code (preferred, keeps state and code in sync). Set the option to
false (or remove it), then run an update so the state records the change, and only then
delete:
const data = new aws.s3.Bucket("data", {
bucket: "prod-data",
}, { protect: false });
pulumi up # applies protect: false to state
# now remove the resource from code (or run destroy) and:
pulumi up # or: pulumi destroy
Unprotect directly from the CLI when you are tearing things down. Target the exact URN from the error message:
pulumi state unprotect 'urn:pulumi:prod::app::aws:s3/bucket:Bucket::data'
Use --all to clear protection from every resource in the stack before a full teardown:
pulumi state unprotect --all
pulumi destroy
Destroy without editing state first. Recent Pulumi CLIs let a destroy remove protected resources when you pass the explicit flag, prompting for confirmation:
pulumi destroy --remove --exclude-protected # skip protected ones
# or, to force through protection:
pulumi destroy # then answer the prompts, or unprotect first
If a replacement is being blocked, decide intent. Either revert the property change to
avoid replacement, or unprotect the resource, let it replace, and re-protect it afterward
with pulumi state protect <urn>.
What to Watch Out For
pulumi state unprotectchanges state immediately and is not a code change — commit an equivalentprotect: false(or intentional re-protect) so code and state stay aligned.- Re-protect important resources after a maintenance operation:
pulumi state protect <urn>. - Protection guards against delete/replace only; it does not prevent in-place property updates.
- Unprotecting
--allbefore a destroy removes every guardrail — double-check you are on the right stack withpulumi stack --show-name. - For data-bearing resources, consider
retainOnDelete: trueso the cloud object survives even if Pulumi drops it from state.
Related Guides
- Pulumi Error: ‘pending operations’ — Troubleshooting Guide
- Pulumi Error: ‘snapshot integrity failure’ — Troubleshooting Guide
- Pulumi Error: ‘resource already exists’ — Troubleshooting Guide
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.