Search code examples
javascriptamazon-web-servicesamazon-s3aws-sdkaws-sdk-js

XML error completing a multi-part upload to S3 with AWS SDK for JavaScript v3


A multi-part upload to S3 is divided in 3 steps:

  • Initiate the multi-part upload
  • Upload parts
  • Complete the multi-part upload

Using AWS SDK for JavaScript v3 (exactly v3.22), the first two steps are successful:

  • The UploadId comes from the initialisation.
  • Each part upload comes with its ETag needed to complete the upload.

The issue comes requesting the upload completion, that is done with:

  const completeParams: CompleteMultipartUploadCommandInput = {
    Bucket,
    Key,
    UploadId,
    MultipartUpload: { Parts },
  };
  return client.send(new CompleteMultipartUploadCommand(completeParams));

Where Parts is an array of valid CompletedPart objects sorted by PartNumber.

Analysing the network call, the request is done to

https://{Bucket}.s3.{Location}.scw.cloud/{Key}?uploadId={UploadId}&x-id=CompleteMultipartUpload

Note: replaced sensible data with placeholders, but they are the expected values.

And the body generated by the AWS SDK is:

<?xml version="1.0" encoding="UTF-8"?>
<CompletedMultipartUpload xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <Part>
    <ETag>&quot;610c4...&quot;</ETag>
    <PartNumber>1</PartNumber>
  </Part>
  <Part>
    <ETag>&quot;2edb4...&quot;</ETag>
    <PartNumber>2</PartNumber>
  </Part>
</CompletedMultipartUpload>

Note: showing just the first 5 chars of each ETag to show that they are different and came from uploading parts.

But the answer from S3 is:

The XML you provided was not well-formed or did not validate against our published schema.

Sequence of calls: enter image description here

Reading the extensive documentation, there is a subtle difference: the root element of the XML should be CompleteMultipartUpload instead of CompletedMultipartUpload, but the XML is generated by the AWS SDK and I would expect it to be right.

What could be wrong?


Solution

  • Issue

    This is an open issue at aws-sdk-js-v3 official repository.

    The error is, indeed, a typo on a XML element. It must be CompleteMultipartUpload instead of CompletedMultipartUpload (extra d).

    Workaround

    Using a middleware that replaces the invalid XML tag, like this:

    const patchS3CompleteMultipartUpload = (client: S3Client): void => {
      client.middlewareStack.add(
        (next, _context) => (args: any) => {
          if ('string' === typeof args.request?.body && args.request.body.includes('CompletedMultipartUpload')) {
            args.request.body = args.request.body.replace(/CompletedMultipartUpload/g, 'CompleteMultipartUpload');
          }
          return next(args);
        },
        {
          step: 'build',
          priority: 'high',
        }
      );
    };