Skip to content

Commit 323e409

Browse files
committed
Strip ChecksumAlgorithm on PutObject to fix R2 SignatureDoesNotMatch
The payload_signing_enabled=False config was ineffective because botocore 1.36+ sets requestChecksumRequired on PutObject, causing aws-chunked transfer encoding with checksum trailers regardless. Register a before-parameter-build event hook to strip ChecksumAlgorithm from PutObject params, preventing the STREAMING-UNSIGNED-PAYLOAD-TRAILER code path that R2 does not support.
1 parent 7134ac3 commit 323e409

File tree

1 file changed

+21
-1
lines changed
  • src/docverse/storage/objectstore

1 file changed

+21
-1
lines changed

src/docverse/storage/objectstore/_s3.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,19 @@ async def open(self) -> None:
8080
signature_version="s3v4",
8181
request_checksum_calculation="when_required",
8282
response_checksum_validation="when_required",
83-
s3={"payload_signing_enabled": False},
8483
),
8584
)
8685
self._client = await self._client_cm.__aenter__()
8786

87+
# Prevent botocore from adding aws-chunked transfer encoding
88+
# with checksum trailers on PutObject. R2 does not support the
89+
# STREAMING-UNSIGNED-PAYLOAD-TRAILER signing protocol that
90+
# botocore 1.36+ uses by default for PutObject.
91+
self._client.meta.events.register(
92+
"before-parameter-build.s3.PutObject",
93+
self._strip_checksum_algorithm,
94+
)
95+
8896
async def close(self) -> None:
8997
"""Close the underlying S3 client."""
9098
if self._client_cm is not None:
@@ -98,6 +106,18 @@ def _get_client(self) -> AioBaseClient:
98106
raise RuntimeError(msg)
99107
return self._client
100108

109+
@staticmethod
110+
def _strip_checksum_algorithm(
111+
params: dict[str, object], **_kwargs: object
112+
) -> None:
113+
"""Remove ChecksumAlgorithm to prevent aws-chunked trailers.
114+
115+
Cloudflare R2 does not support the STREAMING-UNSIGNED-PAYLOAD-TRAILER
116+
signing protocol. Stripping ChecksumAlgorithm from PutObject
117+
parameters prevents botocore from activating this code path.
118+
"""
119+
params.pop("ChecksumAlgorithm", None)
120+
101121
async def generate_presigned_upload_url(
102122
self, *, key: str, content_type: str, expires_in: int = 3600
103123
) -> str:

0 commit comments

Comments
 (0)