AWS Error: NoSuchBucket — S3 Bucket Does Not Exist
An error occurred (NoSuchBucket) when calling the GetObject operation:
The specified bucket does not exist
<Error>
<Code>NoSuchBucket</Code>
<Message>The specified bucket does not exist</Message>
<BucketName>my-prod-bucket-eu</BucketName>
<RequestId>EXAMPLE123</RequestId>
</Error>
NoSuchBucket is S3 saying “I cannot find a bucket by this exact name in the region you queried.” It’s almost always one of three things: a typo, a region mismatch, or a bucket that was deleted (often by a Terraform run or a manual cleanup). The XML response includes the bucket name S3 saw, which is the single most useful clue for debugging — copy it and grep your config.
A debugging tip: S3’s “global namespace, regional data” model trips up almost every team eventually. Bucket names are unique worldwide, but the data and the API endpoint are regional. A bucket named acme-prod-uploads in eu-west-2 cannot be reached by a US-East-1 client without an explicit redirect — and the failure mode is NoSuchBucket, not a clear region error. Pin region explicitly in every long-lived S3 client.
Why this happens
- Typo or stale bucket name in config. Most NoSuchBucket errors are mundane — env var typo, hardcoded name from a deleted resource, Terraform state pointing at a destroyed bucket. Always print the bucket name your code is actually using before assuming a deeper issue.
- Wrong region client for the bucket. S3 bucket names are globally unique but data is regional. A client built with `region_name='us-east-1'` calling a bucket in `eu-west-2` may get NoSuchBucket (newer SDKs auto-redirect; older or misconfigured ones do not). Always pin the region explicitly.
- Bucket was recently deleted. After deletion, the bucket name is reserved for a grace period (up to a few hours) and then released. Calls during the grace period return NoSuchBucket; calls after release may return AccessDenied if someone else recreated the name.
- Path-style vs virtual-hosted-style addressing mismatch. Buckets with dots in the name (`my.bucket.com`) break virtual-hosted-style HTTPS due to wildcard cert mismatch. Some SDKs fall back to path-style; others fail with NoSuchBucket. Use `s3v4` and force path-style addressing for dotted names.
- Cross-account access without the right ARN. Calling a bucket in another account without specifying its full ARN can resolve to your own account's namespace. If your account has no bucket by that name, you get NoSuchBucket — even though the bucket exists in the partner account.
How to fix it
Fixes are ordered by likelihood. Start with the first one that matches your context.
1. Confirm the bucket exists and find its region
`head-bucket` returns 200 if you have access, 403 if it exists but you can't see it, and 404 if it truly doesn't exist. `get-bucket-location` then returns the region. Run both before changing code.
# Does it exist at all?
aws s3api head-bucket --bucket my-prod-bucket-eu
# What region is it in?
aws s3api get-bucket-location --bucket my-prod-bucket-eu
# { "LocationConstraint": "eu-west-2" }
# List your account's buckets to confirm spelling
aws s3 ls
2. Pin the region in your S3 client
Don't rely on default region resolution. Build your S3 client with the bucket's exact region, especially in cross-region or multi-region workloads.
import boto3
# Wrong: client default region may not match the bucket
# s3 = boto3.client('s3')
# Right: pin to the bucket's region
s3 = boto3.client('s3', region_name='eu-west-2')
obj = s3.get_object(Bucket='my-prod-bucket-eu', Key='config.json')
3. Use force_path_style for dotted bucket names
Buckets like `my.site.com` need path-style addressing because HTTPS wildcard certs don't cover three-label subdomains. Newer SDKs handle this automatically; explicitly force it if you're seeing NoSuchBucket on a dotted name.
import boto3
from botocore.client import Config
s3 = boto3.client(
's3',
region_name='us-east-1',
config=Config(s3={'addressing_style': 'path'}, signature_version='s3v4'),
)
4. For cross-account access, use the access point ARN
S3 Access Points let you reach a bucket in another account by ARN, sidestepping global-namespace ambiguity. The ARN includes the owning account and region, so the client can never silently target the wrong account.
5. Print the exact request URL when debugging
Enable SDK debug logging to see the URL the client actually built. Misformatted URLs (double slashes, region prefix in the host) are a frequent root cause that's invisible from the application code.
Detection and monitoring in production
Track NoSuchBucket separately from other 4xx S3 errors. A spike on a single bucket usually means a deletion event in another account. A spike across many buckets in one region usually means a misconfigured deploy pinned the wrong region. CloudTrail `s3:DeleteBucket` events let you correlate quickly.
Related errors
- awsAccessDeniedExceptionThe IAM principal (user, role, or assumed role) making the request does not have an `Allow` statement for the action and resource being called, or an explicit `Deny` somewhere in the evaluation chain blocks it.
- awsThrottlingExceptionYou exceeded the per-second or per-account API request limit for an AWS service. Most AWS APIs use a token bucket — sustained or bursty traffic above the bucket refill rate gets throttled.
Frequently asked questions
What's the difference between NoSuchBucket and AccessDenied on S3? +
My bucket exists but I get NoSuchBucket from a Lambda. Why? +
I just created a bucket but get NoSuchBucket immediately after. Is this a race? +
Why do I see NoSuchBucket only when accessing my bucket from another AWS account? +
Can I recreate a bucket with the same name after deleting it? +
Does NoSuchBucket count toward my S3 request charges? +
How do I detect a bucket-name typo in CI before it ships to production? +
Why do I get NoSuchBucket from a CloudFront-fronted bucket? +
When to escalate to AWS support
Escalate to AWS Support if (a) `aws s3api head-bucket` from the AWS CLI on the same machine returns 200 but your SDK call returns NoSuchBucket — that's a SDK bug or signing issue worth a ticket, (b) the bucket region returned by `get-bucket-location` differs from what you can see in the console, or (c) bucket-name reclaim is taking more than 24 hours after a delete.