Ignacio Lago
Ignacio Lago

Reputation: 2532

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:

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

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?

Upvotes: 2

Views: 2623

Answers (1)

Ignacio Lago
Ignacio Lago

Reputation: 2532

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',
    }
  );
};

Upvotes: 3

Related Questions