Skip to content

Copying large S3 objects from versioning enabled buckets requires s3:GetObjectVersion permission #7117

Description

@kurtismash

Describe the bug

Copying S3 objects larger than 8 MiB the from versioning enabled buckets now requires s3:GetObjectVersion permission.

Regression Issue

  • Select this option if this issue appears to be a regression.

Expected Behavior

When no sourceVersionId is given in the method call, no versionId should be included in the API requests to AWS.

Current Behavior

The API requests to AWS include a versionId parameter, meaning that s3:GetObjectVersion permission is required.

Reproduction Steps

Using a principal who has s3:GetObject but not s3:GetObjectVersion permission attempt to copy a large object in S3 from a versioning enabled bucket.

package com.example.s3copy;

import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3AsyncClient;
import software.amazon.awssdk.services.s3.model.CopyObjectRequest;
import software.amazon.awssdk.transfer.s3.S3TransferManager;
import software.amazon.awssdk.transfer.s3.model.CompletedCopy;
import software.amazon.awssdk.transfer.s3.model.Copy;
import software.amazon.awssdk.transfer.s3.model.CopyRequest;

public class S3MultipartCopy {

    public static void main(String[] args) {
        if (args.length < 4) {
            System.err.println("Usage: S3MultipartCopy <sourceBucket> <sourceKey> <destBucket> <destKey> [region]");
            System.exit(1);
        }

        String sourceBucket = args[0];
        String sourceKey    = args[1];
        String destBucket   = args[2];
        String destKey      = args[3];
        Region region       = args.length >= 5 ? Region.of(args[4]) : Region.US_EAST_1;

        System.out.printf("Copying s3://%s/%s  →  s3://%s/%s (region: %s)%n",
                sourceBucket, sourceKey, destBucket, destKey, region);

        // The CRT-based async client enables multipart copy automatically
        S3AsyncClient crtClient = S3AsyncClient.crtBuilder()
                .region(region)
                .targetThroughputInGbps(10.0)
                .minimumPartSizeInBytes(8 * 1024 * 1024L) // 8 MB minimum part size
                .build();

        try (S3TransferManager transferManager = S3TransferManager.builder()
                .s3Client(crtClient)
                .build()) {
            CopyObjectRequest copyObjectRequest = CopyObjectRequest.builder()
                    .sourceBucket(sourceBucket)
                    .sourceKey(sourceKey)
                    .destinationBucket(destBucket)
                    .destinationKey(destKey)
                    .build();
            CopyRequest copyRequest = CopyRequest.builder()
                    .copyObjectRequest(copyObjectRequest)
                    .build();
            Copy copy = transferManager.copy(copyRequest);
            CompletedCopy result = copy.completionFuture().join();

            System.out.println("Copy complete!");
            System.out.println("ETag: " + result.response().copyObjectResult().eTag());

        } finally {
            crtClient.close();
        }
    }
}

Possible Solution

Looks to be a regression introduced to services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/multipart/CopyObjectHelper.java in ea79934, where the versionId is now always included in the copy request if returned by the head object call.

Additional Information/Context

No response

AWS Java SDK version used

2.47.1

JDK version used

openjdk version "25.0.3" 2026-04-21

Operating System and version

Ubuntu 24.04.4 LTS

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugThis issue is a bug.p1This is a high priority issuepotential-regressionMarking this issue as a potential regression to be checked by team member

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions