GetObjectLegalHold
GetObjectLegalHold tells you whether an object version is under a legal hold: ON while the
version is held, OFF once the hold has been lifted. A version under a legal hold cannot be
deleted or overwritten until the hold is lifted, so this is the question to ask before a clean-up
touches it. Holds are placed and lifted with PutObjectLegalHold, and
they exist in buckets with Object Lock enabled.
- Each bucket is reached through its own regional endpoint, and a bucket in another region
answers
404 NoSuchBucketrather than a redirect. x-amz-expected-bucket-owneris welcome and has nothing to check: a key only ever reaches buckets of its own account.- A key with a
.or..path segment (a/../b) cannot be put in a URL, so STRG answers400 InvalidURIfor it.
When you'd use it
- A clean-up job that skips what is held. A nightly job that permanently deletes old versions with DeleteObject can read each version's legal hold first and leave the held ones for later, rather than meeting an error halfway through.
- Closing a dispute or an investigation. A team that placed holds on a set of contracts can
check which of them are still
ONbefore the matter is closed and the holds are lifted. - Showing a version's state. An internal records tool, or an agent asked whether a document can be removed yet, reads the hold and reports it alongside the version's retention from GetObjectRetention.
Request
GET /photos/2024/cat.jpg?legal-hold 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
The path-style form is GET /my-bucket/photos/2024/cat.jpg?legal-hold on
s3.eu-central-1.strg.com - Addressing explains both.
Permissions
The access key needs Read legal holds (object-legal-hold:read). A key limited to certain
buckets can hold it too, and then reads legal holds in those buckets; a key limited to a
key prefix reads them for objects under that prefix. Access keys
has the details.
URI parameters
| Name | Type | Required | Description |
|---|---|---|---|
Bucket | String | Yes | The bucket holding the object. |
Key | String | Yes | The object's key. A key with a . or .. path segment (a/../b) is answered 400 InvalidURI. |
legal-hold | Flag | Yes | Selects the legal hold subresource. Sent with no value. |
versionId | String | No | The version to read. Without it, the current version. |
A query parameter other than these is answered 501 NotImplemented, so a client knows straight
away; presigning's X-Amz-* parameters and the JavaScript SDK's x-id are always welcome.
Request headers
| Name | Type | Required | Description |
|---|---|---|---|
x-amz-expected-bucket-owner | String | No | Welcome, with nothing to check: an access key only ever reaches its own account's buckets. |
x-amz-request-payer | String | No | Not applicable: STRG has no Requester Pays buckets. |
Request body
None.
Response
A successful request answers 200 OK with the legal hold as XML.
Response headers
| Name | Description |
|---|---|
x-amz-request-id | The request ID, handy for a support request. |
Response body
| Element | Type | Description |
|---|---|---|
LegalHold | Container | The root element. |
Status | String | ON or OFF. |
<?xml version="1.0" encoding="UTF-8"?>
<LegalHold>
<Status>ON</Status>
</LegalHold>
Errors
These are the errors this request can return, and the situation behind each one.
| Code | HTTP status | When |
|---|---|---|
NoSuchBucket | 404 | The 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. |
AccessDenied | 403 | The access key lacks Read legal holds, or the bucket or key is outside its buckets or prefix. |
InvalidAccessKeyId | 403 | The 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. |
InvalidURI | 400 | The key contains a . or .. path segment. |
SignatureDoesNotMatch | 403 | The request signature does not match. |
RequestTimeTooSkewed | 403 | The request time is more than 15 minutes from the server's. |
AuthorizationHeaderMalformed | 400 | The signature's credential scope names a region other than the endpoint's. |
NotImplemented | 501 | The request carries a query parameter other than legal-hold and versionId (presigning's X-Amz-* parameters and the JavaScript SDK's x-id aside). |
SlowDown | 503 | Too many requests. The Retry-After header says when a retry is welcome; the AWS SDKs retry on their own. |
ServiceUnavailable | 503 | A temporary failure; the same request can be retried. |
In a bucket without Object Lock there are no legal holds to read, and the request answers with a
4xx error rather than a Status.
Differences from Amazon S3
The table lists each place where STRG behaves differently, and what that means for a client.
| Aspect | Amazon S3 | STRG |
|---|---|---|
| Bucket in another region | 301 redirect with x-amz-bucket-region | 404 NoSuchBucket. A bucket is reached through its own regional endpoint |
| Nothing stored in the endpoint's region yet | Any valid key reaches the endpoint | 404 NoSuchBucket |
x-amz-expected-bucket-owner | Checked against the bucket owner | Welcome, with nothing to check |
Keys with . or .. segments | Allowed | 400 InvalidURI: such a key cannot be put in a URL, so its legal hold cannot be read |
Examples
Reading the legal hold of the current version of photos/2024/cat.jpg:
- AWS CLI
- Python (boto3)
- JavaScript (AWS SDK v3)
aws s3api get-object-legal-hold \
--bucket my-bucket \
--key photos/2024/cat.jpg \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1
import boto3
s3 = boto3.client(
"s3",
endpoint_url="https://s3.eu-central-1.strg.com",
region_name="eu-central-1",
)
response = s3.get_object_legal_hold(Bucket="my-bucket", Key="photos/2024/cat.jpg")
print(response["LegalHold"]["Status"])
import { GetObjectLegalHoldCommand, S3Client } from "@aws-sdk/client-s3";
const client = new S3Client({
endpoint: "https://s3.eu-central-1.strg.com",
region: "eu-central-1",
});
const response = await client.send(
new GetObjectLegalHoldCommand({ Bucket: "my-bucket", Key: "photos/2024/cat.jpg" }),
);
console.log(response.LegalHold?.Status);
Reading the legal hold of a specific version, whose ID ListObjectVersions lists:
- AWS CLI
- Python (boto3)
- JavaScript (AWS SDK v3)
aws s3api get-object-legal-hold \
--bucket my-bucket \
--key photos/2024/cat.jpg \
--version-id "$VERSION_ID" \
--endpoint-url https://s3.eu-central-1.strg.com \
--region eu-central-1
import os
import boto3
s3 = boto3.client(
"s3",
endpoint_url="https://s3.eu-central-1.strg.com",
region_name="eu-central-1",
)
response = s3.get_object_legal_hold(
Bucket="my-bucket",
Key="photos/2024/cat.jpg",
VersionId=os.environ["VERSION_ID"],
)
print(response["LegalHold"]["Status"])
import { GetObjectLegalHoldCommand, S3Client } from "@aws-sdk/client-s3";
const client = new S3Client({
endpoint: "https://s3.eu-central-1.strg.com",
region: "eu-central-1",
});
const response = await client.send(
new GetObjectLegalHoldCommand({
Bucket: "my-bucket",
Key: "photos/2024/cat.jpg",
VersionId: process.env.VERSION_ID,
}),
);
console.log(response.LegalHold?.Status);