Fix Terraform S3 BucketAlreadyExists and BucketAlreadyOwnedByYou

Tested on Ubuntu 26.04 LTS (Resolute Raccoon)
Package terraform 1.16.1
hashicorp/aws 6.63.0
awscli 2.36.38
Applies to Any host with Terraform and the AWS provider; examples use ap-south-1
Privilege AWS identity with s3:CreateBucket and s3:ListBucket; normal user on the workstation
Scope Diagnose and fix BucketAlreadyExists and BucketAlreadyOwnedByYou from aws_s3_bucket during terraform apply — global S3 namespace rules, importing a bucket your account already owns, and choosing a new unique name when another account holds the name. Does not cover S3 backend state-lock errors, IAM UnauthorizedOperation, or full bucket policy and encryption setup.
Related guides AWS S3 bucket tutorial
Terraform troubleshooting
Fix Terraform S3 state lock error
Short on time?Beta Get the gist of this 8-minute read in seconds, then ask follow-up questions

terraform apply failed while creating an S3 bucket, and the error code tells you which problem you have:

text
Error: creating S3 Bucket (aws): operation error S3: CreateBucket, https response error
StatusCode: 409, RequestID: …, api error BucketAlreadyExists: The requested bucket name is not available.
The bucket namespace is shared by all users of the system. Please select a different name and try again.

or:

text
Error: creating S3 Bucket (glc-tf-bucket-exists-lab-342524208658): operation error S3: CreateBucket,
https response error StatusCode: 409, RequestID: …, api error BucketAlreadyOwnedByYou: Your previous
request to create the named bucket succeeded and you already own it.

Both return HTTP 409 Conflict, but the fix is different. Read the api error line before you rename, import, or destroy anything.


BucketAlreadyExists vs BucketAlreadyOwnedByYou

S3 bucket names are global across every AWS account. The name my-app-state can exist only once worldwide, even though the bucket itself lives in one region.

Error code Who owns the name Smallest correct fix
BucketAlreadyExists Another AWS account (or AWS itself) Choose a different globally unique bucket value
BucketAlreadyOwnedByYou Your current AWS account Import, remove a duplicate declaration, or rename — depending on which stack should own the bucket

Both errors return HTTP 409 Conflict. Read the api error line first; the fix depends on whether your account already owns the bucket, not only on the status code.

BucketAlreadyExists means the global name is unavailable — short names like aws, logs, or data are usually taken before you run apply.

BucketAlreadyOwnedByYou means your account already created that bucket. Common causes:

  • You created it in the console or with the AWS CLI, and this Terraform state does not know about it yet
  • A previous apply created it, but state was lost, switched backends, or you are in a fresh working directory
  • Two stacks or resources hard-code the same bucket value
  • The bucket is already managed by another Terraform workspace, backend, or stack

Check whether your account already owns the bucket

Before you import or rename, list buckets visible to your credentials and look for the exact name from the error:

bash
aws s3api list-buckets --query "Buckets[?Name=='glc-tf-bucket-exists-lab-342524208658'].Name" --output text

Sample output when your account owns it:

output
glc-tf-bucket-exists-lab-342524208658

Read the result together with the Terraform error:

  • Name appears in the list → your account owns the bucket
  • Name does not appear and Terraform reports BucketAlreadyExists → the name is unavailable to your account; pick another one
  • Terraform reports BucketAlreadyOwnedByYou → your account already owns the bucket; decide whether this state should manage it (see below)

Fix BucketAlreadyOwnedByYou

Your account already owns the bucket. The smallest correct fix depends on which configuration should manage it:

text
Your account already owns the bucket.

Should this Terraform state manage that existing bucket?

  Yes  → terraform import
  No, another Terraform stack already manages it → remove the duplicate declaration
  No, this should be a separate bucket → choose a different bucket name

Before you import, confirm the bucket is not already managed by another Terraform state. A single S3 bucket should normally belong to only one Terraform state — importing the same bucket into two states creates two managers for one AWS resource.

Import if this state should manage the bucket

When this working directory is the right owner and the bucket is missing from this state, bring it under management with terraform import.

Example configuration that failed on create:

hcl
resource "aws_s3_bucket" "lab" {
  bucket = "glc-tf-bucket-exists-lab-342524208658"
}

From the directory that contains that resource block, import by bucket name:

bash
terraform import aws_s3_bucket.lab glc-tf-bucket-exists-lab-342524208658

Sample output:

output
aws_s3_bucket.lab: Importing from ID "glc-tf-bucket-exists-lab-342524208658"...
aws_s3_bucket.lab: Import prepared!
  Prepared aws_s3_bucket for import
aws_s3_bucket.lab: Refreshing state... [id=glc-tf-bucket-exists-lab-342524208658]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

Import records ownership in Terraform state; it does not guarantee your HCL already matches the live bucket. Run a plan next:

bash
terraform plan

If your configuration already matches the bucket, you may see:

output
No changes. Your infrastructure matches the configuration.

Otherwise, review the proposed changes before you apply — the plan may want to add versioning, encryption, or other settings your HCL declares but the bucket does not have yet.

Remove the duplicate if another state already manages it

When the bucket is already in another Terraform state — a different workspace, backend key, or repository — remove the duplicate aws_s3_bucket from this configuration instead of importing again.

One physical bucket should map to one Terraform resource in one state file. Delete or refactor the extra declaration, then run terraform plan here to confirm this stack no longer tries to create the bucket.

Use another name if you intended a separate bucket

If this stack is supposed to create a new bucket and the name collision was accidental, change bucket to a unique value (see the next section) rather than importing an existing one.


Fix BucketAlreadyExists

When another account owns the global name, retrying apply with the same string will not succeed. Choose a name that is unique worldwide.

Patterns that work in practice:

  • Append your AWS account ID: glc-tf-bucket-exists-lab-342524208658
  • Add environment and region: myapp-tfstate-prod-ap-south-1
  • Use bucket_prefix and let AWS generate a suffix (names must still be lowercase, 3–63 characters, and follow S3 naming rules)

Example with an account-scoped name:

hcl
data "aws_caller_identity" "current" {}

resource "aws_s3_bucket" "lab" {
  bucket = "myapp-logs-${data.aws_caller_identity.current.account_id}"
}

After you change bucket, run terraform plan — Terraform proposes creating the new bucket and does not silently retarget the old name.

For greenfield state buckets, follow the naming pattern in Configure S3 bucket as Terraform backend so the name stays unique on first apply.


Troubleshooting

Error Root cause Correct action
BucketAlreadyExists Another account already uses the requested bucket name Choose another globally unique bucket value
BucketAlreadyOwnedByYou Bucket created manually (console or CLI) Import if this Terraform state should manage it
BucketAlreadyOwnedByYou Previous apply created it but state was lost or switched Restore the correct state, or import into this state if that is the intended owner
BucketAlreadyOwnedByYou Another Terraform workspace, backend, or stack already manages it Do not import twice — remove the duplicate declaration from this configuration
BucketAlreadyOwnedByYou Two resources or stacks hard-code the same bucket name Rename one bucket or consolidate so one state owns the resource
Import succeeds; plan wants to recreate Provider region does not match the bucket's region Match provider "aws" { region = … } to where the bucket was created

Summary

S3 returns HTTP 409 for both errors, but the api error code answers the three questions you need: what failed, who owns the name, and the smallest fix. BucketAlreadyExists means another account holds the global name — change bucket to something unique, usually with your account ID or environment in the string. BucketAlreadyOwnedByYou means your account already has the bucket — import only if this state should manage it, remove the duplicate resource if another stack already does, or pick a new name if you meant to create a separate bucket.

Use aws s3api list-buckets with a name filter to confirm whether the bucket appears in your account before you import. Never import the same bucket into two Terraform states. Bucket names are shared across all AWS customers, so treat every bucket = "..." value as a global reservation.


References


Frequently Asked Questions

Can I take over a bucket name from another AWS account?

No. S3 bucket names are globally unique. If BucketAlreadyExists appears, only the owning account can use that name until they delete the bucket and the name becomes available again — which is not guaranteed immediately.

Does BucketAlreadyOwnedByYou mean Terraform already managed the bucket?

Not necessarily. It only means your AWS account already created a bucket with that name. Terraform state may be empty, lost, or owned by a different workspace. Import only when this configuration is the right owner — if another stack already manages the bucket, remove the duplicate declaration instead.

Should I use terraform import or aws_s3_bucket import block?

Both work. terraform import on the CLI is the quickest fix for a single existing bucket. An import block in configuration (Terraform 1.5+) suits version-controlled adoption when you want the adoption step recorded in HCL.

Why did a short bucket name like aws fail with BucketAlreadyExists?

Common English words and service names are reserved early across the shared global namespace. Use descriptive names with account ID or random suffixes instead of single-word buckets.

Finished reading?Beta Get the key takeaways in seconds, then ask follow-up questions
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with 15+ years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)