Error: resource already exists
Fix Terraform "resource already exists": run terraform import to adopt the object, or rename yours. Always plan after importing. Covers state drift.
Error: creating S3 Bucket (acme-assets): BucketAlreadyOwnedByYou: Your previous request to create the named bucket succe
Incident Overview
TerraformTerraform
Fix Terraform "resource already exists": run terraform import to adopt the object, or rename yours. Always plan after importing. Covers state drift.
medium fix·6 min read
By Vishvesh Patel·DevOps Engineer·Updated 21 September 2026
Error: creating S3 Bucket (acme-assets): BucketAlreadyOwnedByYou: Your previous request to create the named bucket succeeded and you already own it Error: creating IAM Role (lambda-exec): EntityAlreadyExists: Role with name lambda-exec already exists. Error: InvalidGroup.Duplicate: The security group 'app' already exists for VPC 'vpc-0a1b2c3d'
Do this first3 steps
Run these in order. Each one tells you what its output means before you change anything.
• Check whether Terraform already knows about it
Present in state means the resource is tracked and something else is wrong, usually a name collision with a second configuration. Absent means state and reality have diverged and the object exists outside Terraform's knowledge.
• Import it instead of recreating it
Used with an import block, this writes matching configuration for a resource that already exists, which is far more reliable than hand-writing it and discovering differences during the next apply.
• Verify the import produced no changes
A clean plan after import means your configuration matches reality. Any diff is a real difference between what you wrote and what exists, and applying it will change live infrastructure.
Terraform's plan said "create", the provider said "it is already there". State and reality disagree.
First, establish which:
Not in state. The object exists in the cloud and Terraform does not know about it. Import it, or rename yours.
In state. Terraform thinks it manages it and still tried to create it. Usually a second configuration managing the same object, or a resource that was replaced and the create ran before the destroy.
terraform state list | grep -i assets
How state and reality diverge
The last two are worth checking first if this appeared suddenly.
Fix 1: Import
The right answer when the existing object should be managed by this configuration.
Since Terraform 1.5 use an import block, which is reviewable and runs as part of the plan:
For a resource you have not written configuration for yet, let Terraform generate it:
That writes a matching resource block, which is far more reliable than hand-writing one and discovering the differences during the next apply. Review it before committing; generated configuration includes every attribute, many of which are defaults you would rather omit.
The older CLI form still works:
The import block is preferable because it lives in code, goes through review, and is visible in the plan rather than being an out-of-band command someone ran once.
The import id is resource-specific and is the most common thing to get wrong. Some take a name, some an ARN, some a compound string:
Each resource's provider documentation has an import section. Check it rather than guessing.
import {
to = aws_s3_bucket.assets
id = "acme-assets"
}
resource "aws_s3_bucket" "assets" {
bucket = "acme-assets"
}After importing, always plan
A clean plan means your configuration matches reality. Anything else is a real difference, and applying it changes live infrastructure. A frequent surprise is tags: the existing object has tags your configuration does not, so the plan proposes removing them.
Import brings the object into state with its current attributes. It does not modify the object.
terraform plan
Fix 2: Rename yours
When the existing object belongs to something else and you want a separate one, change the name:
Globally unique namespaces make this common. S3 bucket names are unique across all of AWS, so acme-assets may be owned by a stranger, which surfaces as BucketAlreadyExists rather than BucketAlreadyOwnedByYou. Those two messages are worth distinguishing: one means you own it, the other means somebody else does.
IAM roles and policies are unique per account; security groups are unique per VPC.
For generated names, random_id avoids collisions:
resource "aws_s3_bucket" "assets" {
bucket = "acme-assets-${var.environment}"
}Fix 3: Two configurations own the same object
If a resource is in state and the create still failed, something else may have created it between plan and apply.
Two pipelines applying the same configuration concurrently produce this, and it is the reason state locking exists. Confirm the backend actually locks:
S3 native locking via use_lockfile replaced the DynamoDB table approach in Terraform 1.10. Older configurations use dynamodb_table, which still works.
Without locking, two concurrent applies interleave and produce exactly this class of error.
terraform state list terraform state show aws_s3_bucket.assets
Workspaces and naming
Workspaces isolate state, not names. Applying in dev and then prod creates the second one against an existing IAM role.
resource "aws_iam_role" "lambda" {
name = "lambda-exec" # same in every workspace
}A checklist
Frequently Asked Questions
Should I import the existing resource or delete it?
Import, unless you are certain the object is disposable. Deleting production infrastructure to let Terraform recreate it causes an outage and usually loses data, and for stateful resources such as S3 buckets and RDS instances it may not be recoverable at all. Import brings the object under management with its current attributes and changes nothing about it. The only case for deleting is a genuinely empty leftover from a failed apply that you have verified nothing depends on.
What is the difference between an import block and terraform import?
The CLI command is imperative and runs immediately, so the import happens outside your code and outside review; anyone reading the repository later has no record of it. An import block, available since Terraform 1.5, lives in the configuration, appears in the plan output, and is applied as part of a normal apply. It can also be paired with -generate-config-out to write the matching resource configuration for you. The block is the better default, and you can remove it once the import has been applied.
Why does terraform plan show changes right after an import?
Because import records the object's actual current attributes in state, and your configuration differs from them. The diff is therefore genuine: applying it will modify live infrastructure. Tags are the usual culprit, since the existing object typically has some your configuration omits and the plan proposes removing them. Read the diff carefully and adjust your configuration to match reality, rather than applying and discovering what changed afterwards.
Why do two workspaces conflict on the same resource name?
Workspaces isolate state, not the names of the objects you create. If a resource has a hardcoded name, applying the configuration in a second workspace tries to create a second object with the identical name in the same account, which most providers reject. Include the workspace in generated names, for example "lambda-exec-${terraform.workspace}", or use separate accounts per environment, which is generally the stronger isolation and avoids the whole class of problem.
What does BucketAlreadyOwnedByYou mean, as opposed to BucketAlreadyExists?
BucketAlreadyOwnedByYou means the bucket exists in your own account, so import is available and is almost certainly what you want. BucketAlreadyExists means the name is taken by a different AWS account entirely, because S3 bucket names are globally unique across all of AWS, and no import is possible. In that case you must choose a different name. Distinguishing the two messages saves a lot of time, because they look similar and imply completely different actions.
Reference and practice
Learn the underlying concept
Other Terraform errors
Free, comprehensive DevOps tutorials and learning roadmaps. Master Docker, Kubernetes, CI/CD, and more.
Get notified about new tutorials and features.
• Roadmaps
• Interview Prep
• Certifications
• Company
© 2026 DevOpsLesson. All rights reserved.
Need to practice this scenario?
Simulate this error condition and practice recovery commands safely in our in-browser terminal.