-
Notifications
You must be signed in to change notification settings - Fork 646
Description
Pre-Migration Checklist
- I've read the Migration Guide.
- I've reviewed the upgrading notes and major version differences mentioned in
UPGRADING.md. - I've checked AWS Forums and StackOverflow for similar migration issues.
Which JavaScript Runtime is this issue in?
Node.js (includes AWS Lambda)
AWS Lambda Usage
- Yes, my application is running on AWS Lambda.
- No, my application is not running on AWS Lambda.
Describe the Migration Issue
The S3 ListObjectsV2 result is different when no objects exist for the given prefix. In v2, Contents and CommonPrefixes are empty arrays. In v3, these properties are not present at all in ListObjectsV2CommandOutput, and thus evaluate to undefined. Additionally, in v3, if Delimiter is not passed in the input, CommonPrefixes will be absent in the output, whereas v2 included it as an empty array.
This caused us a production outage. With v2, our code checked for Contents being falsy, but because we could never find a scenario where that actually occurred, we considered it an unexpected error. With v3, the behavior changed unexpectedly.
In my opinion, this is a bad, or at least unconventional API design choice. In most APIs (not AWS specific), if you are searching for any number of matches and getting an array back, and the thing is not found, you get an empty array, rather than the property disappearing. An example is JavaScript's Array#filter method.
I checked all the following documentation and did not see this important difference covered anywhere:
- https://github.com/aws/aws-sdk-js-v3/blob/main/UPGRADING.md
- https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/javascript_s3_code_examples.html
- https://docs.aws.amazon.com/sdk-for-javascript/v3/developer-guide/migrate-s3.html
- https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/command/ListObjectsV2Command/
- https://github.com/aws/aws-sdk-js-v3/blob/main/supplemental-docs/CLIENTS.md
I acknowledge that the documentation says the Contents can be undefined, but it does not say under what circumstances exactly that can occur. In v2, it never occurred. Since the SDK is very sloppy about what can actually be undefined, as often things that are declared | undefined actually never can be (and previously this was the case for this operation), it was an unexpected change.
Code Comparison
V2:
const {Contents} = await client.listObjectsV2(params).promise();
if (!Contents) {
throw new Error(
`Error getting object matching params: ${JSON.stringify(params)}`
);
}
return Contents;V3:
const { Contents } = await client.send(new ListObjectsV2Command(params));
return Contents ?? [];Observed Differences/Errors
Contents is not present in the output when no objects matching the prefix exist.
Additional Context
No response