Skip to main content

CreateMultipartUpload

CreateMultipartUpload is the first step of a multipart upload: it opens an upload for an object and hands back an upload ID. The object's parts then follow with UploadPart or UploadPartCopy, and CompleteMultipartUpload assembles them into the object - or AbortMultipartUpload discards everything. The object's metadata, encryption and Object Lock settings belong to this request, not to the parts.

A single PutObject stores up to 5 GiB, so a larger object travels this way. For any large object, a multipart upload also means parts can go up in parallel, and a part that fails is simply sent again on its own.

Good to know on STRG
  • Parts are 5,000,000 bytes to 5 GiB each (the last part may be smaller), numbered 1-10,000.
  • x-amz-tagging and the Object Lock event-hold headers answer 501 NotImplemented, so a client knows straight away.
  • Encryption is AES256 with STRG-managed keys, or SSE-C with your own key. SSE-KMS answers 501 NotImplemented.
  • An object is always exactly as public as its bucket: x-amz-acl takes private or public-read, matching the bucket's Bucket Protection setting, and x-amz-grant-* headers answer 501 NotImplemented.
  • x-amz-expected-bucket-owner is welcome and has nothing to check: a key only ever reaches buckets of its own account.
  • A bucket in another region answers 404 NoSuchBucket rather than a redirect.
Unfinished uploads are billed

The parts of an upload that is never completed or aborted stay stored, and are billed as stored data. Each upload ends well with either CompleteMultipartUpload or AbortMultipartUpload, and a lifecycle rule that aborts incomplete multipart uploads catches the ones a crashed script leaves behind - Cleaning up abandoned multipart uploads shows one.

When you'd use it​

  • A nightly backup of a database dump or a disk image, often well over 5 GiB. The backup tool starts a multipart upload, sends the file in parts and completes it, so a dropped connection costs one part rather than the whole file.
  • A video platform taking uploads of large recordings. Its server opens the upload here, and the parts can go up in parallel to finish sooner.
  • A data pipeline writing a large export as it is produced. The object's content type and metadata are set once, at the start, and parts follow as the data becomes ready.
  • Anything using the AWS CLI's aws s3 cp or an SDK's transfer helper. Above a size threshold they call CreateMultipartUpload for you, so it is often at work without being called by name.

Request​

POST /photos/2024/cat.jpg?uploads HTTP/1.1
Host: my-bucket.s3.eu-central-1.strg.com
Authorization: AWS4-HMAC-SHA256 Credential=...
x-amz-date: 20260926T120000Z
x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Content-Type: image/jpeg
x-amz-meta-camera: pinhole

Path-style, the same request is POST /my-bucket/photos/2024/cat.jpg?uploads on s3.eu-central-1.strg.com - Addressing explains both forms.

Permissions​

Starting an upload takes Write objects (objects:write). For a key limited to certain buckets or to a key prefix, the bucket and the object key need to be within them.

Locking the object as it is uploaded takes a little more, the same permission setting the lock afterwards would:

HeaderAlso takes
x-amz-object-lock-mode, x-amz-object-lock-retain-until-dateSet retention (object-retention:write)
x-amz-object-lock-legal-holdSet legal holds (object-legal-hold:write)

Without it, STRG answers 403 AccessDenied. Access keys has every permission.

URI parameters​

NameTypeRequiredDescription
BucketStringYesThe bucket to upload into.
KeyStringYesThe key of the object to create. A key with a . or .. path segment (a/../b) cannot be put in a URL, and STRG answers 400 InvalidURI.
uploads-YesPresent, with no value. It marks the request as CreateMultipartUpload.

Any other query parameter is answered with 501 NotImplemented.

Request headers​

NameTypeRequiredDescription
Cache-ControlStringNoStored with the object and returned when it is read.
Content-DispositionStringNoStored with the object and returned when it is read.
Content-EncodingStringNoStored with the object and returned when it is read.
Content-LanguageStringNoStored with the object and returned when it is read.
Content-TypeStringNoThe object's media type, returned when it is read.
ExpiresTimestampNoStored with the object and returned when it is read.
x-amz-meta-*StringNoUser-defined metadata, stored with the object.
x-amz-aclStringNoprivate or public-read, and only the value that matches the bucket: private for a bucket with Bucket Protection on, public-read for one with it off. Any other canned ACL is 501 NotImplemented. An object is always exactly as public as its bucket.
x-amz-grant-full-controlStringNo501 NotImplemented: access comes from the access key and the bucket's Bucket Protection.
x-amz-grant-readStringNo501 NotImplemented.
x-amz-grant-read-acpStringNo501 NotImplemented.
x-amz-grant-write-acpStringNo501 NotImplemented.
x-amz-server-side-encryptionStringNoAES256 encrypts the object with STRG-managed keys. aws:kms and aws:kms:dsse are 501 NotImplemented.
x-amz-server-side-encryption-customer-algorithmStringNoSSE-C: AES256. The same three SSE-C headers go on every UploadPart of the upload.
x-amz-server-side-encryption-customer-keyStringNoSSE-C: your base64-encoded 256-bit key. STRG does not store it, so losing it means losing the object.
x-amz-server-side-encryption-customer-key-MD5StringNoSSE-C: the base64-encoded MD5 digest of the key.
x-amz-server-side-encryption-aws-kms-key-idStringNo501 NotImplemented.
x-amz-server-side-encryption-contextStringNo501 NotImplemented.
x-amz-server-side-encryption-bucket-key-enabledBooleanNo501 NotImplemented.
x-amz-storage-classStringNoSTRG has a single storage class, so this header is best left out.
x-amz-website-redirect-locationStringNoSTRG does not host static websites, so this header has nothing to act on and is best left out.
x-amz-taggingStringNo501 NotImplemented. Objects carry no tags.
x-amz-object-lock-modeStringNoGOVERNANCE or COMPLIANCE. Works in a bucket with Object Lock enabled, together with x-amz-object-lock-retain-until-date, and takes the Set retention permission. Object Lock explains the modes.
x-amz-object-lock-retain-until-dateTimestampNoWhen the retention ends, in ISO 8601 (2027-01-01T00:00:00Z). Takes Set retention.
x-amz-object-lock-legal-holdStringNoON or OFF. Works in a bucket with Object Lock enabled and takes the Set legal holds permission.
x-amz-object-lock-event-holdStringNo501 NotImplemented.
x-amz-object-lock-event-hold-duration-daysIntegerNo501 NotImplemented.
x-amz-object-lock-event-hold-duration-yearsIntegerNo501 NotImplemented.
x-amz-checksum-algorithmStringNoThe checksum algorithm the parts will carry, such as CRC32. Every part then sends a checksum of that algorithm.
x-amz-checksum-typeStringNoAccepted and passed on with the request.
x-amz-expected-bucket-ownerStringNoWelcome, with nothing to check: an access key only ever reaches its own account's buckets.
x-amz-request-payerStringNoNot applicable: STRG has no Requester Pays buckets.

Every x-amz-* header in the request is part of the signature - the AWS CLI and SDKs take care of that. One left unsigned is answered with 403 AccessDenied.

Request body​

None.

Response​

A successful request answers 200 OK with the upload ID in an XML body.

Response headers​

NameDescription
x-amz-request-idThe request ID, handy for support requests.
x-amz-server-side-encryptionThe server-side encryption used for the object, when it is encrypted.
x-amz-server-side-encryption-customer-algorithmFor SSE-C, the algorithm you sent.
x-amz-server-side-encryption-customer-key-MD5For SSE-C, the MD5 digest of the key you sent.
x-amz-checksum-algorithmThe checksum algorithm of the upload, when you set one.
x-amz-checksum-typeThe checksum type of the upload, when there is one.

x-amz-server-side-encryption-aws-kms-key-id, x-amz-server-side-encryption-context, x-amz-server-side-encryption-bucket-key-enabled and x-amz-request-charged are never returned. x-amz-abort-date and x-amz-abort-rule-id are not something to count on for learning whether a lifecycle rule will abort the upload; the bucket's rules, read with GetBucketLifecycleConfiguration, are the reliable answer.

Response body​

ElementDescription
BucketThe bucket the upload is in.
KeyThe object key the upload is for.
UploadIdThe upload ID. Every later request for this upload carries it unchanged; it is an opaque string.
<?xml version="1.0" encoding="UTF-8"?>
<InitiateMultipartUploadResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Bucket>my-bucket</Bucket>
<Key>photos/2024/cat.jpg</Key>
<UploadId>EXAMPLE-UPLOAD-ID</UploadId>
</InitiateMultipartUploadResult>

Errors​

These are the answers a CreateMultipartUpload can get besides 200 OK, and the situation behind each:

CodeHTTP statusWhen
NoSuchBucket404The bucket does not exist, or it is in a region other than the endpoint's.
InvalidURI400The key contains a . or .. path segment, such as a/../b. Nothing is started.
AccessDenied403The access key lacks Write objects, or Set retention / Set legal holds for an Object Lock header, or the bucket or key is outside its buckets or object prefix, or an x-amz-* header is not signed.
NotImplemented501The request carries x-amz-tagging, an event-hold header, SSE-KMS, an x-amz-grant-* header, a canned ACL other than private or public-read, or a query parameter this operation does not take.
InvalidAccessKeyId403The access key does not exist, has expired or been revoked, or it is not yet usable in a region where you already store data - a key created a moment ago, which works again shortly.
SignatureDoesNotMatch403The request signature does not match.
RequestTimeTooSkewed403The request time is more than 15 minutes from the server's.
AuthorizationHeaderMalformed400The signature's credential scope names a region other than the endpoint's.
SlowDown503Too many requests at once. The SDKs retry after the Retry-After interval.
ServiceUnavailable503A temporary failure; the request succeeds when retried.

Differences from Amazon S3​

Most of these make STRG simpler to reason about; each says what a client sees.

AspectAmazon S3STRG
Part size5 MiB minimum (except the last part), 5 GiB maximum5,000,000 bytes minimum (except the last part), 5 GiB maximum
Part numbers1-10,0001-10,000
Bucket in another region301 redirect with x-amz-bucket-region404 NoSuchBucket. The bucket's own regional endpoint reaches it
x-amz-taggingTags the object501 NotImplemented
Object Lock event holdsSupported501 NotImplemented
SSE-KMSSupported501 NotImplemented. AES256 with STRG-managed keys, or SSE-C
ACLsAny canned ACL, and grantsprivate or public-read, matching the bucket. Grants are 501 NotImplemented
Storage classesSeveralOne, so x-amz-storage-class is best left out
Website redirectsx-amz-website-redirect-locationSTRG does not host static websites
Object Lock headersNeed s3:PutObjectRetention / s3:PutObjectLegalHoldTake Set retention / Set legal holds on the access key
x-amz-expected-bucket-ownerChecked against the bucket ownerNothing to check: a key reaches only its own account's buckets
Keys with a . or .. path segmentAccepted400 InvalidURI

Examples​

Starting an upload​

This starts an upload for photos/2024/cat.jpg with a content type and one metadata entry, and keeps the upload ID for the parts that follow:

UPLOAD_ID=$(aws s3api create-multipart-upload \
--bucket my-bucket \
--key photos/2024/cat.jpg \
--content-type image/jpeg \
--metadata camera=pinhole \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1 \
--query UploadId \
--output text)
echo "$UPLOAD_ID"

Uploading a large file​

The high-level transfer tools call CreateMultipartUpload, UploadPart and CompleteMultipartUpload for you, and abort the upload if it fails. A custom part size works anywhere between 5,000,000 bytes and 5 GiB, as long as the whole file fits in 10,000 parts.

aws s3 cp ./backup.tar s3://my-bucket/backups/backup.tar \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1

Locking the object as it is uploaded​

In a bucket with Object Lock enabled, this starts an upload whose object is retained in governance mode until 1 January 2027. The access key takes Set retention beside Write objects.

aws s3api create-multipart-upload \
--bucket my-bucket \
--key photos/2024/cat.jpg \
--object-lock-mode GOVERNANCE \
--object-lock-retain-until-date 2027-01-01T00:00:00Z \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1
View as Markdown