---
title: UploadPartCopy · S3 API
description: Copies a byte range of an object into one part of a multipart upload.
doc_version: 0.1.0-preview
last_updated: 2026-09-14
---

# UploadPartCopy

`PUT /{bucket}/{key}?partNumber&uploadId` with the `x-amz-copy-source` header

Copies a byte range of an object into one part of a multipart upload.

Use it to build a large object from objects that you already stored, with no download.

- Role: Editor or higher.
- Support: partial.
- Auth: AWS Signature Version 4 with your API key. See [S3 API](/api/s3.md).
- The source must be in the same bucket. One byte range per part.

## Example request

```http
PUT /support-tickets/big.bin?partNumber=2&uploadId=VXBsb2FkIGZvciBiaWcuYmlu HTTP/1.1
Host: wspq7ws2np5l8z4.storage.beta.graphon.sh
x-amz-date: 20261007T093000Z
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Authorization: AWS4-HMAC-SHA256 Credential=<ACCESS_KEY_ID>/20261007/us-east-1/s3/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date, Signature=<SIGNATURE>
x-amz-copy-source: support-tickets/archive.bin
x-amz-copy-source-range: bytes=0-104857599
```

## Path parameters

- `bucket` (string, required): The bucket name.
- `key` (string, required): The object key. Keep each `/` as it is. Percent-encode the other reserved characters.

## Query parameters

- `partNumber` (integer, required): The part number, from 1 through 10,000.
- `uploadId` (string, required): The upload ID from CreateMultipartUpload.

## Headers

- `x-amz-copy-source` (string, required): The source object, as `{bucket}/{key}`, URL-encoded. Add `?versionId=` to copy one version.
- `x-amz-copy-source-range` (string, optional): One byte range of the source, for example `bytes=0-104857599`. Without it, storage copies the whole source.
- `x-amz-expected-bucket-owner` (string, optional): The workspace ID that must own the bucket. Another owner returns `403 AccessDenied`.

## Responses

### 200 · OK

Storage copied the part.

Response body:

- `CopyObjectResult` (object, required): The root element.
  - `LastModified` (string, optional): When storage copied the part.
  - `ETag` (string, optional): The entity tag of the part. Send it to CompleteMultipartUpload.

```http
HTTP/1.1 200 OK
Content-Type: application/xml
x-amz-request-id: 4F8A2C7D1E6B4093A5C2D8E1F7B3A960

<?xml version="1.0" encoding="UTF-8"?>
<CopyObjectResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
  <LastModified>2026-10-07T09:30:00.000Z</LastModified>
  <ETag>"0cc175b9c0f1b6a831c399e269772661"</ETag>
</CopyObjectResult>
```

## Errors

Any request can also get the common errors on [S3 API](/api/s3.md).

### 404 · `NoSuchUpload`

The upload ID is not known for this key. The upload was completed or aborted.

Start a new upload with CreateMultipartUpload.

### 400 · `InvalidArgument`

The partNumber is not an integer from 1 through 10,000.

Number the parts from 1 through 10,000.

### 404 · `NoSuchKey`

The source has no object at this key or version.

Check the key and the versionId.

### 501 · `NotImplemented`

The source is in another bucket.

Copy parts from objects in the same bucket only.

### 400 · `InvalidRequest`

The `x-amz-copy-source` value is not `{bucket}/{key}`.

Send the source as `{bucket}/{key}`, URL-encoded.

### 503 · `SlowDown`

The bucket has too many writes in progress. The response has `Retry-After: 1`.

Wait for the Retry-After time, then send the request again. SDKs retry by themselves.

### 404 · `NoSuchBucket`

No bucket has this name, or the bucket was deleted.

Check the bucket name. ListBuckets shows the buckets of the workspace.

### 403 · `AccessDenied`

The key does not have the role for this operation, or the bucket is in another workspace.

Use a key of the workspace that owns the bucket, with the role above.

## Other request languages

### aws CLI

```bash
# The graphon profile from the S3 API overview.
export AWS_PROFILE=graphon

UPLOAD_ID="VXBsb2FkIGZvciBiaWcuYmlu"  # The UploadId from create-multipart-upload
aws s3api upload-part-copy \
  --bucket support-tickets \
  --key big.bin \
  --part-number 2 \
  --upload-id "$UPLOAD_ID" \
  --copy-source support-tickets/archive.bin \
  --copy-source-range bytes=0-104857599
```

### Python (boto3)

```python
# Replace wspq7ws2np5l8z4 with your workspace ID.
import os

import boto3
from botocore.config import Config

api_key = os.environ["GRAPHON_API_KEY"]
access_key_id = api_key.split("_", 1)[1].split(".")[0]

s3 = boto3.client(
    "s3",
    endpoint_url="https://wspq7ws2np5l8z4.storage.beta.graphon.sh",
    region_name="us-east-1",
    aws_access_key_id=access_key_id,
    aws_secret_access_key=api_key,
    config=Config(signature_version="s3v4", s3={"addressing_style": "path"}),
)

upload_id = "VXBsb2FkIGZvciBiaWcuYmlu"  # The UploadId from create_multipart_upload
response = s3.upload_part_copy(
    Bucket="support-tickets",
    Key="big.bin",
    PartNumber=2,
    UploadId=upload_id,
    CopySource="support-tickets/archive.bin",
    CopySourceRange="bytes=0-104857599",
)
print(response["CopyPartResult"]["ETag"])
```

### JavaScript (AWS SDK)

```javascript
// Replace wspq7ws2np5l8z4 with your workspace ID.
import { S3Client, UploadPartCopyCommand } from '@aws-sdk/client-s3';

const apiKey = process.env.GRAPHON_API_KEY;
if (!apiKey) throw new Error('Set GRAPHON_API_KEY.');
const accessKeyId = apiKey.split('_')[1].split('.')[0];

const s3 = new S3Client({
  endpoint: 'https://wspq7ws2np5l8z4.storage.beta.graphon.sh',
  region: 'us-east-1',
  forcePathStyle: true,
  credentials: { accessKeyId, secretAccessKey: apiKey },
});

const uploadId = 'VXBsb2FkIGZvciBiaWcuYmlu'; // The UploadId from CreateMultipartUpload
const response = await s3.send(new UploadPartCopyCommand({
  Bucket: 'support-tickets',
  Key: 'big.bin',
  PartNumber: 2,
  UploadId: uploadId,
  CopySource: 'support-tickets/archive.bin',
  CopySourceRange: 'bytes=0-104857599',
}));
console.log(response.CopyPartResult?.ETag);
```

## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
