SRJ
SRJ

Reputation: 2806

S3Exception when trying to complete multi-part upload using the AWS Java v2 SDK

I'm trying to complete a multi-part upload to S3 in Java 11, using the AWS SDK for Java v2.

My CompleteMultipartUploadRequest initially looked like this, and functionally worked:

CompleteMultipartUploadRequest completeMultipartUploadRequest = CompleteMultipartUploadRequest
                .builder()
                .bucket(s3BucketName)
                .key(fileName)
                .uploadId(uploadId)
                .multipartUpload(CompletedMultipartUpload.builder().parts(completedParts).build())
                .build();
CompleteMultipartUploadResponse completedUploadResponse = s3Client.completeMultipartUpload(completeMultipartUploadRequest);
return completedUploadResponse.location();

However, Sonar was complaining about:

Consider using the Consumer Builder method instead of creating this nested builder.

So I made a minor change in the request:

CompleteMultipartUploadRequest completeMultipartUploadRequest = CompleteMultipartUploadRequest
                .builder()
                .bucket(s3BucketName)
                .key(fileName)
                .uploadId(uploadId)
                .multipartUpload(completedParts -> CompletedMultipartUpload.builder().parts(completedParts).build())
                .build();
CompleteMultipartUploadResponse completedUploadResponse = s3Client.completeMultipartUpload(completeMultipartUploadRequest);
return completedUploadResponse.location();

The Sonar warning went away, but then the upload started throwing the below exception:

Exception in thread "main" software.amazon.awssdk.services.s3.model.S3Exception: The XML you provided was not well-formed or did not validate against our published schema (Service: S3, Status Code: 400, Request ID: xxx, Extended Request ID: xxx) at software.amazon.awssdk.protocols.xml.internal.unmarshall.AwsXmlPredicatedResponseHandler.handleErrorResponse(AwsXmlPredicatedResponseHandler.java:156)

What's the issue?

Upvotes: 1

Views: 1478

Answers (1)

Ermiya Eskandary
Ermiya Eskandary

Reputation: 23582

The consumer method, which you're using here, has a signature of multipartUpload(Consumer<CompletedMultipartUpload.Builder> multipartUpload).

In your updated code, you are passing a function that takes a list of CompletedPart objects as input & returns a CompletedMultipartUpload object.

This doesn't match the signature as you're not passing in a consumer which just takes in the builder.

Update your code to simply just set the parts on the provided builder object - you don't need to build it yourself.

This is stated by the documentation for the method as well:

This is a convenience that creates an instance of the CompletedMultipartUpload.Builder avoiding the need to create one manually via CompletedMultipartUpload.builder().

Try this instead:

CompleteMultipartUploadRequest completeMultipartUploadRequest = CompleteMultipartUploadRequest.builder()
                .bucket(bucketName)
                .key(keyName)
                .uploadId(uploadId)
                .multipartUpload(completedMultipartUpload -> completedMultipartUpload.parts(completedParts))
                .build();

Upvotes: 1

Related Questions