Skip to main content

PutObjectRetention

PutObjectRetention sets the retention of an object version: its mode, governance or compliance, and the date until which it is locked. Without versionId it sets the current version's. Retention exists only in a bucket with Object Lock enabled, and reading one back is the job of GetObjectRetention.

Good to know on STRG
  • Setting a retention takes the Set retention permission on the access key. Shortening, removing or changing a governance-mode lock takes Bypass governance retention as well.
  • x-amz-expected-bucket-owner is welcome and has nothing to check: a key only ever reaches buckets of its own account.
  • A key containing a . or .. path segment (a/../b) cannot be put in a URL, so STRG answers 400 InvalidURI for it.
  • The body is sent whole: an aws-chunked body is answered with 501 NotImplemented, and the AWS SDKs do not send this operation's body that way by default.
A lock stays until its date

A locked object version cannot be deleted permanently until its retention date has passed, and it is billed as stored data until then. A compliance-mode lock cannot be shortened or removed by anyone - it can only be extended. Once set, that version is kept, and billed, until the date it names.

When you'd use it​

  • Keeping one backup longer. A bucket's default retention locks every new backup for a few weeks; the backup taken at the end of a quarter can have its lock extended to a year, so it outlasts the rest.
  • Records that must be kept. A system archiving invoices or contracts locks each one in compliance mode until the end of the period the law asks for, so nobody - an administrator included - can remove it early.
  • Protecting files after the fact. An object uploaded before anyone thought to lock it can be given a retention later, version by version.
  • Correcting a mistake. A governance-mode lock set further out than intended can be shortened by a key holding Bypass governance retention - the one way back governance mode leaves open.

Request​

PUT /photos/2024/cat.jpg?retention 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: <SHA-256 of the body, hex>
Content-MD5: <MD5 of the body, base64>
Content-Type: application/xml

<?xml version="1.0" encoding="UTF-8"?>
<Retention xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Mode>GOVERNANCE</Mode>
<RetainUntilDate>2027-01-01T00:00:00.000Z</RetainUntilDate>
</Retention>

The path-style form is PUT /my-bucket/photos/2024/cat.jpg?retention on s3.eu-central-1.strg.com, which a bucket name containing a dot needs - Addressing explains both.

Permissions​

Which permissions a request needs depends on the change it makes:

ChangePermissions needed
Setting a retention on a version that has none, or extending one to a later dateSet retention (object-retention:write)
Moving a compliance-mode retention to a later dateSet retention (object-retention:write)
Shortening or removing a governance-mode retention, or changing it to compliance modeSet retention and Bypass governance retention (object-retention:bypass-governance), with x-amz-bypass-governance-retention: true on the request
Shortening or removing a compliance-mode retentionNo permission allows it: a compliance-mode retention only ever gets longer

A request carrying x-amz-bypass-governance-retention: true from a key without Bypass governance retention answers 403 AccessDenied, whether or not the change needed it. For a key limited to certain buckets or to a key prefix, the bucket and the object key are within them. Access keys has the details.

URI parameters​

NameTypeRequiredDescription
BucketStringYesThe bucket holding the object.
KeyStringYesThe object key. A key containing a . or .. path segment answers 400 InvalidURI.
retention-YesSelects this operation. Takes no value.
versionIdStringNoThe version whose retention to set; without it, the current version's. A version ID is an opaque string.

Any other query parameter is answered with 501 NotImplemented, so a client knows straight away. The X-Amz-* parameters of a presigned URL and the x-id parameter the JavaScript SDK adds are welcome.

Request headers​

NameTypeRequiredDescription
x-amz-bypass-governance-retentionBooleanNotrue to shorten, remove or change a governance-mode retention. Takes Bypass governance retention on the access key. Has no effect on a compliance-mode retention.
Content-MD5StringNoThe base64 MD5 digest of the body. A digest that does not match the body answers 400 BadDigest. The AWS SDKs send an integrity header by default.
x-amz-checksum-crc32, x-amz-checksum-crc32c, x-amz-checksum-crc64nvme, x-amz-checksum-sha1, x-amz-checksum-sha256StringNoA checksum of the body, accepted in place of Content-MD5.
x-amz-sdk-checksum-algorithmStringNoThe algorithm of the x-amz-checksum-* header the SDK sends beside it. Accepted.
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.

Request body​

A Retention document, UTF-8, up to 2 MiB, sent whole - an aws-chunked body is answered with 501 NotImplemented.

<?xml version="1.0" encoding="UTF-8"?>
<Retention xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<Mode>COMPLIANCE</Mode>
<RetainUntilDate>2027-01-01T00:00:00.000Z</RetainUntilDate>
</Retention>
ElementTypeRequiredDescription
RetentionContainerYesThe object version's new retention.
ModeStringNoGOVERNANCE or COMPLIANCE. How it works explains what each allows.
RetainUntilDateTimestampNoThe date and time, in UTC and ISO 8601 form, until which the version cannot be deleted permanently.

Response​

A successful request answers 200 OK with no body.

Response headers​

NameDescription
x-amz-request-idThe request ID, handy for a support request.
x-amz-request-chargedNot returned: STRG has no Requester Pays buckets.

Response body​

None.

Errors​

These are the errors this request can return, and the situation behind each one.

CodeHTTP statusWhen
NotImplemented501The request carries a query parameter other than retention and versionId (presigning's X-Amz-* parameters and x-id aside), or an aws-chunked body.
NoSuchBucket404The bucket does not exist, it is in a region other than the endpoint's, or the account has no storage in this endpoint's region.
NoSuchKey404The object does not exist.
AccessDenied403The access key lacks Set retention, or sends x-amz-bypass-governance-retention: true without Bypass governance retention, or the bucket or key is outside its buckets or prefix.
InvalidAccessKeyId403The access key does not exist, has expired or been revoked - or it was created moments ago and is not usable yet in a region where the account already stores data, in which case the same request works shortly afterwards.
InvalidURI400The key contains a . or .. path segment.
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.
BadDigest400Content-MD5 does not match the body.
XAmzContentSHA256Mismatch400x-amz-content-sha256 does not match the body.
MalformedXML400The body is not valid UTF-8, or not a valid Retention document.
MaxMessageLengthExceeded400The body is larger than 2 MiB.
SlowDown503Too many requests. The Retry-After header says when a retry is welcome; the AWS SDKs retry on their own.
ServiceUnavailable503A temporary failure; the same request can be retried.
InternalError500An unexpected failure; the same request can be retried.

A request that would shorten or remove a compliance-mode retention, that would shorten, remove or change a governance-mode retention without x-amz-bypass-governance-retention: true, or that names an object in a bucket without Object Lock, answers a 4xx error and changes nothing - the existing lock stays exactly as it was.

Differences from Amazon S3​

The table lists each place where STRG behaves differently, and what that means for a client.

AspectAmazon S3STRG
Permissionss3:PutObjectRetention, plus s3:BypassGovernanceRetention to bypassSet retention (object-retention:write), plus Bypass governance retention (object-retention:bypass-governance) on the access key
x-amz-expected-bucket-ownerChecked against the bucket ownerWelcome, with nothing to check
Bucket in another region301 redirect with x-amz-bucket-region404 NoSuchBucket. A bucket is reached through its own regional endpoint
Nothing stored in the endpoint's region yetAny valid key reaches the endpoint404 NoSuchBucket, since the account has no buckets there
Keys with . or .. segmentsAllowed400 InvalidURI, because such a key cannot be put in a URL
aws-chunked request bodyAccepted501 NotImplemented. The SDKs send this operation's body whole by default, so it does not come up in everyday use

Examples​

Locking the current version of photos/2024/cat.jpg in governance mode until 1 January 2027:

aws s3api put-object-retention \
--bucket my-bucket \
--key photos/2024/cat.jpg \
--retention '{"Mode":"GOVERNANCE","RetainUntilDate":"2027-01-01T00:00:00Z"}' \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1

Shortening the governance-mode retention of a specific version, which takes Bypass governance retention on the access key, with VERSION_ID set to a version ID from ListObjectVersions:

aws s3api put-object-retention \
--bucket my-bucket \
--key photos/2024/cat.jpg \
--version-id "$VERSION_ID" \
--retention '{"Mode":"GOVERNANCE","RetainUntilDate":"2026-10-31T00:00:00Z"}' \
--bypass-governance-retention \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1
View as Markdown