Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for Pulumi By James Joyner IV · · 8 min read

Pulumi Error: 'resource cannot be deleted because it is protected' — Cause, Fix, and Troubleshooting Guide

Quick answer

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
Free toolkit

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 destroy aborts and lists one or more protected resources it refuses to delete.
  • pulumi up fails when a change would replace a protected resource (a replacement is a delete + create).
  • Removing a resource from your program and running pulumi up errors instead of deleting it.
  • The message always names the resource by its full URN and tells you to set protect to false.

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 unprotect changes state immediately and is not a code change — commit an equivalent protect: 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 --all before a destroy removes every guardrail — double-check you are on the right stack with pulumi stack --show-name.
  • For data-bearing resources, consider retainOnDelete: true so the cloud object survives even if Pulumi drops it from state.
Free download · 368-page PDF

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.