boto3 Unable to locate credentials / You must specify a region (tested)
boto3 raises NoCredentialsError: Unable to locate credentials on the first API call when nothing in its credential chain (arguments, env vars, ~/.aws, roles) has keys, and NoRegionError: You must specify a region. when a regional client is created with no region set.
1. Both errors, on a machine with no AWS config
import boto3, botocore.exceptions as be
try:
boto3.client("s3").list_buckets() # region not needed for S3
except be.NoCredentialsError as e:
print(type(e).__name__, "|", e)
try:
boto3.client("dynamodb")
except be.NoRegionError as e:
print(type(e).__name__, "|", e)
print("region used:", boto3.client("dynamodb", region_name="eu-west-1").meta.region_name)
Output:
NoCredentialsError | Unable to locate credentials
NoRegionError | You must specify a region.
region used: eu-west-1
NoCredentialsError: Unable to locate credentials is raised when the client makes its first API call, not when you create it: boto3 walked its whole credential chain and found nothing. NoRegionError: You must specify a region. is raised earlier, when you create a client for a regional service without any region configured. The S3 client above was created without a region; DynamoDB was not. Pass region_name= or configure a default.
2. Where boto3 looks, and the profile trap
import os, boto3
os.environ["AWS_ACCESS_KEY_ID"] = "AKIAEXAMPLE"
os.environ["AWS_SECRET_ACCESS_KEY"] = "example"
os.environ["AWS_DEFAULT_REGION"] = "us-east-1"
s = boto3.Session()
c = s.get_credentials()
print("credentials from:", c.method, "| region:", s.region_name)
os.environ["AWS_PROFILE"] = "work" # profile not in ~/.aws/config
try:
boto3.Session()
except Exception as e:
print(type(e).__name__, "|", e)
Output:
credentials from: env | region: us-east-1
ProfileNotFound | The config profile (work) could not be found
boto3 checks, in order: arguments to the client or Session, environment variables (AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY, region from AWS_DEFAULT_REGION), then the shared files ~/.aws/credentials and ~/.aws/config for the selected profile, then container and instance roles. credentials.method tells you which source won (env here). If AWS_PROFILE names a profile that is not in your config files, you get ProfileNotFound as soon as the Session is created.
Common reasons it works in your shell but not elsewhere: the script runs as another user or under cron/systemd, so ~/.aws is a different home directory or the env vars are missing; inside Docker, where your host's ~/.aws is not mounted; or aws configure was run for a named profile but the code uses the default one.
Checklist
- Run
aws sts get-caller-identity(orboto3.Session().get_credentials()) as the same user, in the same environment, as the failing code. - Set a region:
region_name="...",AWS_DEFAULT_REGION, orregionin~/.aws/config. - Docker: pass env vars or mount the AWS config directory read-only; on AWS itself, prefer an IAM role over keys.
ProfileNotFound: check the spelling ofAWS_PROFILEagainst the[profile ...]sections in~/.aws/config.- Never hard-code keys in the source; the env-var values above are dummies.
Frequently asked questions
Why does boto3 say Unable to locate credentials?
No credentials were found in client arguments, environment variables, ~/.aws/credentials or config for the active profile, or an IAM role. Check as the same user and environment that runs the code.
How do I fix botocore NoRegionError You must specify a region?
Pass region_name to boto3.client(), set AWS_DEFAULT_REGION, or add region to your profile in ~/.aws/config.
How do I see where boto3 got its credentials?
boto3.Session().get_credentials().method returns the source, e.g. env or shared-credentials-file.
Written with AI assistance. Measured on 2026-10-23 with boto3/botocore 1.43.118 and Python 3.14.7 (python:3-alpine in Docker, no ~/.aws, AWS_EC2_METADATA_DISABLED=true so boto3 does not probe an instance role). Each block was run verbatim and the output pasted unedited. PlainHeaders is our extension; Python and boto3 are free.