SignatureDoesNotMatch: The request signature we calculated does not match
Fix S3 SignatureDoesNotMatch: sync the system clock, strip whitespace from the secret key, and set the right region. Also covers proxies and presigned URLs.
An error occurred (SignatureDoesNotMatch) when calling the ListObjectsV2 operation: The request signature we calculated
Incident Overview
Fix S3 SignatureDoesNotMatch: sync the system clock, strip whitespace from the secret key, and set the right region. Also covers proxies and presigned URLs.
medium fix·5 min read
By Vishvesh Patel·DevOps Engineer·Updated 21 September 2026
An error occurred (SignatureDoesNotMatch) when calling the ListObjectsV2 operation: The request signature we calculated does not match the signature you provided. Check your key and signing method. <Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided.</Message></Error> An error occurred (AuthorizationHeaderMalformed) when calling the GetObject operation: The authorization header is malformed; the region 'us-east-1' is wrong; expecting 'eu-west-1'
Do this first3 steps
Run these in order. Each one tells you what its output means before you change anything.
• Check the clock first, it costs nothing
Signature Version 4 includes a timestamp and AWS rejects anything more than 15 minutes out. A suspended laptop or a VM restored from a snapshot is the usual source, and the error gives no hint that time is involved.
• Look for whitespace or quoting damage in the secret key
od shows a trailing newline or space that is invisible in an editor. A key pasted from a wrapped terminal, or set in a YAML file without quoting, is a very common cause.
• Confirm the region matches the bucket
SigV4 binds the signature to a region. Signing for us-east-1 against a bucket in eu-west-1 produces AuthorizationHeaderMalformed, which names both regions and is the clearest variant of this error.
The signature you sent does not match the one AWS computed from the same request. Because SigV4 signs the method, path, query string, several headers, the payload hash, the timestamp, the region and the service, anything that alters one of those on the way produces this.
It is rarely a wrong secret key, though that is where people look first.
timedatectl status 2>/dev/null | head -5 || date -u
Check the clock
SigV4 includes X-Amz-Date, and AWS rejects requests more than 15 minutes from its own clock. No part of the error mentions time, so this is easy to miss.
Laptops resumed from long suspends, VMs restored from snapshots, and containers on a host with a drifting clock are the usual sources. Inside a container the clock comes from the host, so fix it there.
timedatectl status | head -5 date -u
Look for whitespace in the key
A trailing space or newline is invisible in an editor and breaks the HMAC. Common sources:
Special characters matter too. A secret key containing / or + inside an unquoted shell variable, or embedded in a URL, gets mangled.
aws configure get aws_secret_access_key | od -c | tail -3
Confirm the region
A null result means us-east-1, which is a quirk worth knowing.
Signing for the wrong region gives a more specific message:
That variant is the friendly one, because it names both. Set the region explicitly:
aws s3api get-bucket-location --bucket acme-assets
A proxy rewriting the request
Any middlebox that modifies signed headers breaks the signature:
Host is always signed, so anything that changes it invalidates the signature. Content-Type is frequently signed too.
Test with the proxy bypassed:
env | grep -i proxy curl -sv https://acme-assets.s3.eu-west-1.amazonaws.com/ 2>&1 | grep -i "^< "
Presigned URLs
Things that break a presigned URL:
Expiry. Maximum is 7 days for SigV4, and 12 hours when signed with a role's temporary credentials, because the URL cannot outlive the session that created it.
The credential expired. A presigned URL created with a role session dies when that session does, regardless of the expiry you asked for.
Extra query parameters. Anything appended after signing, including analytics parameters added by a link shortener or an email tracker, invalidates the signature.
Re-encoding. A URL passed through something that re-encodes %2F or + in the signature breaks it. Presigned URLs should be treated as opaque.
aws s3 presign s3://acme-assets/report.pdf --expires-in 3600
Uploads with a changed body
For PutObject, the payload hash is signed. Anything that alters the body in transit breaks it:
For large uploads, use multipart, which signs each part independently and is more robust as well as resumable.
S3-compatible endpoints
MinIO, Cloudflare R2, Backblaze B2 and similar implement SigV4 with differences. Two settings usually matter:
Virtual-hosted addressing puts the bucket in the hostname, which changes the signed Host header. Many self-hosted endpoints only support path style.
Some also require a specific region string, often us-east-1, regardless of where they run.
aws configure set default.s3.addressing_style path aws --endpoint-url https://minio.internal:9000 s3 ls
A checklist
Frequently Asked Questions
Why does a valid secret key produce SignatureDoesNotMatch?
Because the signature covers far more than the key: the HTTP method, the canonical path and query string, several headers including Host, a hash of the payload, the timestamp, the region and the service. Anything that differs between what you signed and what AWS received produces a mismatch. In practice the most common causes are a clock more than 15 minutes out, invisible whitespace on the end of the key, the wrong region, and a proxy rewriting headers in transit.
How much clock drift does AWS tolerate?
Fifteen minutes in either direction. Beyond that the request is rejected, and nothing in the error message mentions time, which makes it a frustrating thing to chase. Check with date -u against a known-good source and restart your NTP service. Machines that suspend for long periods, virtual machines restored from snapshots, and containers inheriting a drifted host clock are the usual offenders; inside a container you must fix the host.
Why does my presigned URL stop working before it expires?
Most likely because it was signed with temporary credentials from an assumed role, and a presigned URL cannot outlive the session that created it. A URL requested with a twelve hour expiry but signed by a one hour role session dies after an hour. The other common cause is something appending query parameters after signing, such as a link shortener or an email tracker adding analytics, since every query parameter is part of the signed request.
What does AuthorizationHeaderMalformed mean?
It is the region variant of the same problem, and it is the most helpful version because it names both the region you signed for and the one the bucket is in. SigV4 binds a signature to a specific region, so signing for us-east-1 against a bucket in eu-west-1 cannot validate. Run aws s3api get-bucket-location to get the real region, remembering that a null result means us-east-1.
Why does this happen against MinIO or R2 but not AWS?
Because S3-compatible endpoints implement SigV4 with small differences, most often around addressing style. AWS defaults to virtual-hosted addressing, which puts the bucket name in the hostname and therefore in the signed Host header, while many self-hosted endpoints only support path-style addressing. Set aws configure set default.s3.addressing_style path. Some implementations also require a particular region string, commonly us-east-1, regardless of where they actually run.
Reference and practice
Learn the underlying concept
Other AWS errors
Free, comprehensive DevOps tutorials and learning roadmaps. Master Docker, Kubernetes, CI/CD, and more.
Get notified about new tutorials and features.
• Roadmaps
• Interview Prep
• Certifications
• Company
© 2026 DevOpsLesson. All rights reserved.
Need to practice this scenario?
Simulate this error condition and practice recovery commands safely in our in-browser terminal.