| Tested on | Ubuntu 26.04 LTS (Resolute Raccoon) |
|---|---|
| Package | terraform 1.16.1hashicorp/aws 6.63.0awscli 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 |
terraform apply failed while creating an S3 bucket, and the error code tells you which problem you have:
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:
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
applycreated it, but state was lost, switched backends, or you are in a fresh working directory - Two stacks or resources hard-code the same
bucketvalue - 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:
aws s3api list-buckets --query "Buckets[?Name=='glc-tf-bucket-exists-lab-342524208658'].Name" --output textSample output when your account owns it:
glc-tf-bucket-exists-lab-342524208658Read 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:
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 nameBefore 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:
resource "aws_s3_bucket" "lab" {
bucket = "glc-tf-bucket-exists-lab-342524208658"
}From the directory that contains that resource block, import by bucket name:
terraform import aws_s3_bucket.lab glc-tf-bucket-exists-lab-342524208658Sample 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:
terraform planIf your configuration already matches the bucket, you may see:
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_prefixand let AWS generate a suffix (names must still be lowercase, 3–63 characters, and follow S3 naming rules)
Example with an account-scoped name:
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
- Amazon S3 bucket naming rules — length, characters, and global uniqueness
- CreateBucket API —
BucketAlreadyExistsandBucketAlreadyOwnedByYouerror semantics - Terraform AWS provider: aws_s3_bucket — resource arguments and import syntax
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.

