Skip to content

Request signing drops range header, causing SignatureDoesNotMatch error. #9682

@DrewMcArthur

Description

@DrewMcArthur

Describe the bug

I'm attempting to get a range of bytes from a specific file in S3, but it's returning a SignatureDoesNotMatch error. The canonical request included in the error shows an empty byte range. Removing the byte range from the request works fine.

Regression Issue

  • Select this option if this issue appears to be a regression. Works in 1.42.19, botocore 1.40.19

Expected Behavior

I'd expect these requests to work, but the signatures don't match, which returns a 403 instead of a 200.

Current Behavior

aws s3api get-object --bucket my-bucket --key 'path/to/my.parquet' out.parquet --range bytes=-8 --debug

returns (truncated for brevity and security)

b'<?xml version="1.0" encoding="UTF-8"?>\n<Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
<AWSAccessKeyId>MYACCESSKEYID</AWSAccessKeyId>
<StringToSign>AWS4-HMAC-SHA256\n20250827T223046Z\n20250827/us-east-1/s3/aws4_request\n075ccc80f98639364d215440cc4dda8d67cb9f82f12fb09fc36fff50196f8018</StringToSign><SignatureProvided>736c1cbf683e496dc7c099e5e9d95894bab216a6437e418ac812ac10441b8d46</SignatureProvided>
<CanonicalRequest>
GET
/path/to/my.parquet

host:my-bucket.s3.us-east-1.amazonaws.com
range:
x-amz-checksum-mode:ENABLED
x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
x-amz-date:20250827T223046Z

host;range;x-amz-checksum-mode;x-amz-content-sha256;x-amz-date;x-amz-security-token
<hash>
</CanonicalRequest>

whereas the same command, less the --range param, works fine.

aws s3api get-object --bucket my-bucket --key 'path/to/my.parquet' out.parquet --debug

I can't imagine why this would be, other than the piece where range is included in the canonical request, but the header value is missing.

I am able to generate a presigned URL, then curl that with the range header, and that works:

aws s3 presign s3://my-bucket/my-key --expires-in 60 > url.txt
curl -v -H "Range: bytes=-8" "$(cat url.txt)"

Reproduction Steps

Included above

Possible Solution

either removing range from the canonical request that the signature is created from (i assume that's how the presigned url generation works) or including the range value in the request being signed.

Additional Information/Context

No response

CLI version used

aws-cli/2.28.16 Python/3.13.7 Windows/11 exe/AMD64

Environment details (OS name and version, etc.)

Windows 11

Metadata

Metadata

Assignees

Labels

bugThis issue is a bug.p3This is a minor priority issuepotential-regressionMarking this issue as a potential regression to be checked by team members3s3api

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions