-
Notifications
You must be signed in to change notification settings - Fork 646
Description
Checkboxes for prior research
- I've gone through Developer Guide and API reference
- I've checked AWS Forums and StackOverflow.
- I've searched for previous similar issues and didn't find any solution.
Describe the bug
When S3 receives a streaming body (e.g., STREAMING-AWS4-HMAC-SHA256-PAYLOAD), it requires a minimum chunk size of 8 KiB (see: Signature Calculations for the Authorization Header: Transferring Payload in Multiple Chunks (Chunked Upload) (AWS Signature Version 4)).
Consolidating chunks smaller than 8 KiB is performed by @smithy/util-stream:createBufferedReadable, but createBufferedReadable is only used if requestStreamBufferSize is at least 8 KiB:
aws-sdk-js-v3/packages/middleware-flexible-checksums/src/flexibleChecksumsMiddleware.ts
Lines 128 to 139 in 3b6a4d9
| updatedBody = getAwsChunkedEncodingStream( | |
| typeof config.requestStreamBufferSize === "number" && config.requestStreamBufferSize >= 8 * 1024 | |
| ? createBufferedReadable(requestBody, config.requestStreamBufferSize, context.logger) | |
| : requestBody, | |
| { | |
| base64Encoder, | |
| bodyLengthChecker, | |
| checksumLocationName, | |
| checksumAlgorithmFn, | |
| streamHasher, | |
| } | |
| ); |
The issue is that the default S3Client configuration does not initialize requestStreamBufferSize, so it defaults to 0 and streaming input data is not buffered. This causes multiple problems:
-
If the input stream yields chunks smaller than 8 KiB, S3 rejects the request:
<?xml version="1.0" encoding="UTF-8"?> <Error> <Code>InvalidChunkSizeError</Code> <Message>Only the last chunk is allowed to have a size less than 8192 bytes</Message> <Chunk>2</Chunk> <BadChunkSize>1</BadChunkSize> <RequestId>MFV9HHNYNX34P0CR</RequestId> <HostId>W2Ui7jGmxqjbC4YDNBFlkwMOpvvOLiFfG3/+hKwkDf17y+RjG0DXgK5Ys6E9NqUChL3BAVDdTsM=</HostId> </Error>
-
Even worse, if the input stream produces an empty (zero-byte) chunk, the lack of buffering results in the chunk being serialized as
0\r\n\r\n, which prematurely signals the end of theaws-chunkedbody and causes a malformed trailer error:<?xml version="1.0" encoding="UTF-8"?> <Error> <Code>MalformedTrailerError</Code> <Message>The request contained trailing data that was not well-formed or did not conform to our published schema.</Message> <RequestId>SQXM6H16K11AK9WQ</RequestId> <HostId>esc1L1ccaETEivpB096+T4kI0Q+bM5q7+Q7x6yKoaLe+jfK6FEQmR08EeHljLiqmBBB59a/Sqcmim9F2YQ04VCp7uDOwaf8GpaZyy4+Ondo=</HostId> </Error>
The above errors are fixed by explicitly passing the minimum chunk size to S3Client:
const s3Client = new S3Client({
+ requestStreamBufferSize: 8 * 1024,
});Why is it that S3Client does not default requestStreamBufferSize to 8 * 1024, as above? This causes the aforementioned errors, which don't seem obvious (and I personally spent the last few days debugging this).
Regression Issue
- Select this option if this issue appears to be a regression.
SDK version number
@aws-sdk/[email protected]
Which JavaScript Runtime is this issue in?
Node.js
Details of the browser/Node.js/ReactNative version
Node.js v24.11.0
Reproduction Steps
See https://github.com/mxxk-examples/aws-sdk-js-v3-issue-7509.
Observed Behavior
Depending on the test, S3 errors out with InvalidChunkSizeError or MalformedTrailerError, as seen above.
Expected Behavior
S3Client properly buffers chunks smaller than 8 KiB (which also tolerates empty chunks from the input stream) without the caller needing to know about or supply requestStreamBufferSize.
Possible Solution
Make S3Client default requestStreamBufferSize to 8 * 1024 (8 KiB).
Additional Information/Context
Related issues:
-
Streaming contents to S3 fails in latest typescript s3 sdk #7048
This issue proposes a workaround, but does not address the core pain point (lack of sane default for
requestStreamBufferSize). -
Support for minimum chunk size handling in streaming uploads (re: WHEN_REQUIRED) #6949
This issue points to the need to provide
requestStreamBufferSize, but it's not clear to me the design decision to not defaultrequestStreamBufferSize.