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

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.