TL;DR
You're hitting An error occurred (NoSuchBucket) when calling the operation because one of three things happened: the bucket name is wrong, the bucket lives in a different AWS region than you expect, or it was deleted. Start with the name, then the region.
# Does the bucket actually exist?
aws s3 ls s3://your-bucket-name
# If that fails, find where it actually lives
aws s3api get-bucket-location --bucket your-bucket-name
Root Cause
S3 bucket names are globally unique โ but buckets themselves are regional. When AWS throws NoSuchBucket, it can't find the bucket you're referencing in the region your client is targeting. The bucket might not exist at all, or your SDK is just talking to the wrong region endpoint.
The error shows up in a few forms depending on the operation:
An error occurred (NoSuchBucket) when calling the PutObject operation: The specified bucket does not exist
An error occurred (NoSuchBucket) when calling the GetObject operation: The specified bucket does not exist
An error occurred (NoSuchBucket) when calling the ListObjectsV2 operation: The specified bucket does not exist
Five culprits account for roughly 95% of cases:
- Region mismatch โ bucket is in
ap-southeast-1but your client is targetingus-east-1 - Typo in bucket name โ names are case-sensitive, hyphens only (no underscores)
- Bucket was deleted โ someone ran
terraform destroy, or a teammate cleaned up the wrong environment - Wrong AWS account โ you're authenticated to staging but the bucket is in production
- Stale environment variable โ
BUCKET_NAMEstill points to the old bucket from last quarter
Fix Step by Step
Step 1 โ Verify the bucket exists
# List all buckets in the account
aws s3 ls
# Check if this specific bucket is there
aws s3 ls s3://your-bucket-name 2>&& echo "EXISTS" || echo "NOT FOUND"
If your bucket doesn't appear in aws s3 ls, it's either deleted or sitting in a different account.
Step 2 โ Find the bucket's actual region
aws s3api get-bucket-location --bucket your-bucket-name
Example output:
{
"LocationConstraint": "ap-southeast-1"
}
A null value means the bucket is in us-east-1 โ that's just how AWS represents it. Make sure your SDK or CLI matches this region exactly.
Step 3 โ Fix region in AWS CLI
# Pass the region explicitly per command
aws s3 cp file.txt s3://your-bucket-name/ --region ap-southeast-1
# Or pin it for the whole session
export AWS_DEFAULT_REGION=ap-southeast-1
Step 4 โ Fix region in boto3 (Python)
import boto3
# Hard-code the region โ don't rely on environment defaults in production
s3 = boto3.client('s3', region_name='ap-southeast-1')
try:
s3.put_object(Bucket='your-bucket-name', Key='test.txt', Body=b'hello')
except s3.exceptions.NoSuchBucket as e:
print(f"Bucket not found: {e}")
except Exception as e:
print(f"Other error: {e}")
Step 5 โ Fix region in AWS SDK for Node.js
const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');
// Explicit region โ never rely on SDK auto-detection here
const s3 = new S3Client({ region: 'ap-southeast-1' });
try {
await s3.send(new PutObjectCommand({
Bucket: 'your-bucket-name',
Key: 'test.txt',
Body: 'hello',
}));
} catch (err) {
if (err.name === 'NoSuchBucket') {
console.error('Bucket not found โ check name and region');
}
}
Step 6 โ Recreate the bucket if it was deleted
# Create in a specific region (required outside us-east-1)
aws s3api create-bucket \
--bucket your-bucket-name \
--region ap-southeast-1 \
--create-bucket-configuration LocationConstraint=ap-southeast-1
# us-east-1 is the exception โ omit LocationConstraint
aws s3api create-bucket --bucket your-bucket-name --region us-east-1
One catch: if a different AWS account already owns that bucket name globally, you'll get BucketAlreadyExists. Pick a different name โ there's no way around global uniqueness.
Step 7 โ Confirm you're in the right account
aws sts get-caller-identity
Output:
{
"UserId": "AIDA...",
"Account": "123456789012",
"Arn": "arn:aws:iam::123456789012:user/your-user"
}
Wrong account number? Switch profiles and verify again:
export AWS_PROFILE=production
aws sts get-caller-identity
Step 8 โ Hunt down stale environment variables
# Check what your shell thinks the bucket is
echo $AWS_DEFAULT_REGION
echo $BUCKET_NAME
echo $S3_BUCKET
# Running in Docker? Check inside the container
docker exec your-container env | grep -i bucket
docker exec your-container env | grep -i aws
Stale env vars pointing to a deleted or renamed bucket cause more production incidents than most people admit. A deployment from six months ago quietly set BUCKET_NAME=myapp-prod-old and nobody noticed until 2 AM.
Verification
Run a full round-trip test before closing the incident:
# Write a test object
echo "test" | aws s3 cp - s3://your-bucket-name/healthcheck.txt --region ap-southeast-1
# Read it back
aws s3 cp s3://your-bucket-name/healthcheck.txt - --region ap-southeast-1
# Clean up
aws s3 rm s3://your-bucket-name/healthcheck.txt
All three commands succeed without errors? Your bucket is accessible and the config is solid.
Preventive Measures
- Hard-code the region in every SDK client โ auto-detection is fine locally, not in production
- Store bucket names in SSM Parameter Store or Secrets Manager instead of hardcoded strings โ eliminates typos and makes rotation painless
- Add a bucket existence check to your app's startup or health check endpoint so broken config fails loudly at boot, not mid-request
- Enable S3 Versioning and MFA Delete on critical buckets โ one accidental
terraform destroywon't wipe your data permanently - Tag every bucket with
Environment(prod/staging) andTeamโ when you're incident-hunting at midnight, these tags save real time

