IaC Error Guide: 'resource already exists' Pulumi Update Failed
Fix Pulumi's 'update failed / resource already exists' error: reconcile drifted state, import out-of-band resources, clear partial updates, and remove protect.
- #iac
- #troubleshooting
- #errors
- #pulumi
Overview
This error happens when Pulumi tries to create a resource during pulumi up, but the underlying cloud provider reports that an object with the same name or identifier is already present. Pulumi’s state file has no record of the resource, so it plans a create; the cloud API then rejects the create because the real object exists. The update aborts and the stack is left partially applied.
You will see this at the end of a pulumi up:
Diagnostics:
aws:s3:Bucket (assets):
error: creating S3 Bucket (my-bucket-name): operation error S3: CreateBucket,
https response error StatusCode: 409, BucketAlreadyOwnedByYou: Your previous
request to create the named bucket succeeded and you already own it.
pulumi:pulumi:Stack (infra-prod):
error: update failed
It occurs whenever the desired state in code diverges from what Pulumi has tracked in state: a resource created outside Pulumi, a previous update that failed after the cloud object was created but before state was written, or a duplicate logical name. The fix is almost always to reconcile state with reality rather than to keep retrying pulumi up.
Symptoms
pulumi upends witherror: update failedand a provider409/AlreadyExistsdiagnostic.- The resource exists in the cloud console but not in
pulumi stack export. - A prior
pulumi upwas interrupted (Ctrl-C, CI timeout) and now reports a pending operation. pulumi destroycannot remove a resource because of aprotectflag.
pulumi up --yes
Updating (prod):
Type Name Status Info
pulumi:pulumi:Stack infra-prod **failed** 1 error
+ └─ aws:s3:Bucket assets **creating failed** 1 error
Diagnostics:
aws:s3:Bucket (assets):
error: creating S3 Bucket (my-bucket-name): ... BucketAlreadyOwnedByYou
Common Root Causes
1. The resource was created out-of-band and is not in state
Someone created the object manually (console, CLI, another tool), so Pulumi has no URN for it and tries to create it again.
pulumi stack export | jq '.deployment.resources[].urn' | grep -i bucket
aws s3api head-bucket --bucket my-bucket-name
(no matching URN in state)
(head-bucket returns 0 — the bucket exists in AWS)
The bucket exists in AWS but not in Pulumi state, so the create collides.
2. A previous update failed after creating the cloud object
The provider created the resource, but Pulumi crashed or was cancelled before recording it. State is missing the resource even though the API call succeeded.
pulumi stack export | jq '.deployment.pending_operations'
[
{
"type": "creating",
"resource": {
"urn": "urn:pulumi:prod::infra::aws:s3/bucket:Bucket::assets"
}
}
]
A non-empty pending_operations means the last update was interrupted mid-flight.
3. Duplicate logical (resource) name in the program
Two resources declared with the same logical name and the same physical name resolve to the same cloud object, so the second create collides.
grep -rn 'new aws.s3.Bucket' ./
./index.ts:14:const assets = new aws.s3.Bucket("assets", { bucket: "my-bucket-name" });
./storage.ts:9:const cdn = new aws.s3.Bucket("cdn", { bucket: "my-bucket-name" });
Two different logical names but the same hard-coded bucket value both want my-bucket-name.
4. Stale state vs. the real cloud (drift)
State claims the resource was deleted (or never existed), but it is still live in the provider. A pulumi refresh reveals the gap.
pulumi refresh --diff --yes
Refreshing (prod):
~ aws:s3:Bucket assets refreshing
- aws:s3:Bucket assets deleted
Resources:
- 1 deleted
Refresh marks the resource deleted in state, but the bucket still exists in AWS — the next up will try to recreate it and collide.
5. The resource is marked protect
A protect: true resource cannot be replaced or deleted, so any plan that needs to recreate it blocks the update.
pulumi stack export | jq '.deployment.resources[] | select(.protect==true) | .urn'
"urn:pulumi:prod::infra::aws:s3/bucket:Bucket::assets"
The resource is protected; Pulumi refuses to replace it and the update cannot proceed.
6. Importing an existing resource without import semantics
You want Pulumi to adopt an existing object, but the program uses a plain new declaration instead of pulumi import or an import resource option, so Pulumi tries to create rather than adopt.
pulumi up --yes 2>&1 | grep -i 'already'
error: creating ... already exists; use `pulumi import` to adopt the existing resource
Pulumi explicitly tells you the object must be imported, not created.
Diagnostic Workflow
Step 1: Read the exact failing resource and provider error
pulumi up 2>&1 | tail -30
Note the resource type, logical name, and the physical name/ID in the provider error (e.g. my-bucket-name). That physical ID drives every later step.
Step 2: Check whether the resource is in state
pulumi stack export | jq '.deployment.resources[] | select(.type=="aws:s3/bucket:Bucket") | {urn, id}'
If the physical ID is absent from state but present in the cloud, this is an out-of-band or import case (causes 1 and 6).
Step 3: Look for interrupted updates
pulumi stack export | jq '.deployment.pending_operations'
pulumi cancel
A non-empty pending_operations means a prior run was interrupted. pulumi cancel clears the lock so you can re-run safely.
Step 4: Reconcile drift with refresh
pulumi refresh --diff
This re-reads the real cloud state into Pulumi. It surfaces resources that were deleted-in-state-but-live, or properties that drifted out-of-band.
Step 5: Adopt, delete, or unprotect as appropriate
# Adopt an existing object into state instead of creating it:
pulumi import aws:s3/bucket:Bucket assets my-bucket-name
# Or drop a stale/duplicate entry from state (does NOT touch the cloud):
pulumi state delete 'urn:pulumi:prod::infra::aws:s3/bucket:Bucket::assets'
# Or remove protection so the update can proceed:
pulumi state unprotect 'urn:pulumi:prod::infra::aws:s3/bucket:Bucket::assets'
Then re-run pulumi up.
Example Root Cause Analysis
A CI pipeline running pulumi up for stack prod fails on every run with BucketAlreadyOwnedByYou for my-bucket-name. Retrying does not help.
First, confirm the bucket is missing from state but live in AWS:
pulumi stack export | jq '.deployment.resources[].id' | grep my-bucket-name
aws s3api head-bucket --bucket my-bucket-name && echo "exists in AWS"
(no output from the jq filter)
exists in AWS
The bucket exists in AWS but Pulumi has no record of it. Checking the git history shows the bucket was created last quarter with the AWS console during an incident, before it was ever added to the Pulumi program. Now that the code declares it, Pulumi plans a fresh create that collides.
The correct fix is to adopt the existing object into state rather than recreate it:
pulumi import aws:s3/bucket:Bucket assets my-bucket-name
Importing (prod):
= aws:s3:Bucket assets imported
Resources:
= 1 imported
warning: aws:s3/bucket:Bucket has been deprecated... (review generated code)
Pulumi prints the resource definition it expects in code; align the program with it, then re-run:
pulumi up --yes
The bucket is now tracked in state, the create becomes a no-op, and the update succeeds.
Prevention Best Practices
- Treat the cloud console as read-only for Pulumi-managed accounts. Out-of-band creates are the single most common cause of
already exists. Codify all changes; see our infrastructure-as-code guides. - Run
pulumi refreshon a schedule (or in CI beforeup) so drift surfaces as a diff instead of a failed update. - Never
kill -9or hard-cancel a runningpulumi up. If a run is interrupted, runpulumi canceland inspectpending_operationsbefore retrying. - Keep physical names (
bucket,name) unique across the program, or let Pulumi auto-name resources to avoid duplicate-name collisions. - Adopt pre-existing infrastructure with
pulumi import(orpulumi import --from) rather than declaring it withnewand hoping the apply reconciles. - When triaging a failed
pulumi uplog under pressure, the free incident assistant can summarize the diagnostic into the likely state-vs-cloud cause.
Quick Command Reference
# See the full failure with the physical ID
pulumi up 2>&1 | tail -30
# Is the resource in state?
pulumi stack export | jq '.deployment.resources[] | {urn, id}'
# Check for an interrupted update and clear the lock
pulumi stack export | jq '.deployment.pending_operations'
pulumi cancel
# Reconcile state with the real cloud
pulumi refresh --diff
# Adopt an existing object instead of creating it
pulumi import aws:s3/bucket:Bucket assets my-bucket-name
# Remove a stale/duplicate entry from state (cloud untouched)
pulumi state delete '<URN>'
# Allow replacement/deletion of a protected resource
pulumi state unprotect '<URN>'
# Re-run the update
pulumi up --yes
Conclusion
A Pulumi update failed with resource already exists means the program wants to create an object that already exists in the cloud but is absent from (or stale in) Pulumi state. The usual root causes:
- The resource was created out-of-band and never imported into state.
- A previous update was interrupted after the cloud object was created.
- Two resources resolve to the same physical name (duplicate name).
- State drifted from the real cloud and a refresh is overdue.
- A
protectflag blocks the replacement the plan requires. - An existing resource was declared with
newinstead of being imported.
Reconcile state with reality first — pulumi refresh, then pulumi import to adopt or pulumi state delete to prune — rather than retrying pulumi up against a colliding object.
Download the Free 500-Prompt DevOps AI Toolkit
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.