DeleteObject
DeleteObject deletes an object. Every STRG bucket keeps versions of its objects, so a delete comes in two kinds, and which one happens depends on whether the request names a version:
| Request | Effect | Permission |
|---|---|---|
No versionId | Writes a delete marker, which becomes the object's current version. The object disappears from listings and reads, and every earlier version is kept | Write objects |
With versionId | Permanently deletes that version, or removes that delete marker | Delete object versions |
For many objects at once, DeleteObjects takes up to a thousand in one request.
- Versioning is always on, so a delete without
versionIdnever removes data: an object deleted by mistake comes back when its delete marker is deleted. - A permanent delete needs Delete object versions, rather than Write objects.
- Conditional deletes (
If-Match,x-amz-if-match-last-modified-time,x-amz-if-match-size) andx-amz-mfaare answered with501 NotImplemented, and nothing is deleted. x-amz-expected-bucket-owneris welcome and has nothing to check: a key only ever reaches buckets of its own account.
A delete marker hides an object; it does not remove it. Every earlier version stays billed as
stored data until it is deleted by versionId or a
lifecycle policy removes it. A permanent delete cannot be undone.
When you'd use it
- An app removing what a user deleted. A photo-sharing app deletes
photos/2024/cat.jpgwhen its owner removes it. The delete marker hides it at once, and the earlier version is still there if the user changes their mind. - Recovering from a mistake. A script that deleted the wrong file can list its versions with ListObjectVersions and delete the delete marker by its version ID - the object is back exactly as it was.
- Freeing storage for good. A clean-up job that has to make data truly gone - a customer's
export after its download window, or an old build artifact - deletes each version by
versionId, so it no longer counts as stored data. - An agent tidying its workspace. An agent keeping scratch files in a bucket deletes the ones it no longer needs, the same way any S3 client does.
Request
DELETE /photos/2024/cat.jpg 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 DELETE /my-bucket/photos/2024/cat.jpg on s3.eu-central-1.strg.com,
which a bucket name containing a dot needs - Addressing explains
both.
Permissions
Which permission the access key needs depends on the request:
| Request | Permission |
|---|---|
Without versionId | Write objects (objects:write) |
With versionId | Delete object versions (objects:delete-versions). Write objects alone is not enough, and is not needed |
With x-amz-bypass-governance-retention: true | Bypass governance retention (object-retention:bypass-governance), in addition to the above |
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
| Name | Type | Required | Description |
|---|---|---|---|
Bucket | String | Yes | The bucket holding the object. |
Key | String | Yes | The object key. A key containing a . or .. path segment (a/../b) cannot be put in a URL, so DeleteObjects, which carries the key in the request body, is the way to delete it. |
versionId | String | No | The version to delete permanently. Naming a delete marker's version ID removes the marker, and the previous version becomes current again. Without it, a delete marker is written. |
Any other query parameter is answered with 501 NotImplemented.
Request headers
| Name | Type | Required | Description |
|---|---|---|---|
x-amz-bypass-governance-retention | Boolean | No | true permanently deletes a version locked in governance mode, with Bypass governance retention. It has no effect on compliance mode or a legal hold. Object Lock has the details. |
x-amz-mfa | String | No | STRG has no MFA Delete, and answers 501 NotImplemented. |
If-Match | String | No | STRG answers 501 NotImplemented, and nothing is deleted. |
x-amz-if-match-last-modified-time | Timestamp | No | STRG answers 501 NotImplemented, and nothing is deleted. |
x-amz-if-match-size | Long | No | STRG answers 501 NotImplemented, and nothing is deleted. |
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 | Has no effect: STRG has no Requester Pays buckets. |
Request body
None.
Response
A successful delete answers 204 No Content with no body.
Response headers
| Name | Description |
|---|---|
x-amz-delete-marker | true when the request wrote a delete marker, or when the version it permanently deleted was a delete marker. |
x-amz-version-id | Without versionId: the version ID of the new delete marker. With versionId: the version that was deleted. Version IDs are opaque strings. |
x-amz-request-id | The request ID, useful when asking support about a request. |
x-amz-request-charged is never returned.
Response body
None.
Errors
These are the errors a delete can return, and the situation behind each one.
| Code | HTTP status | When |
|---|---|---|
NotImplemented | 501 | The request carries x-amz-mfa, If-Match, x-amz-if-match-last-modified-time, x-amz-if-match-size, or a query parameter other than versionId. Nothing is deleted. |
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 the permission the request needs (see Permissions), 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. DeleteObjects can delete it. |
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. |
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. |
A version under retention or a legal hold stays until its lock ends, and a permanent delete
of it does not go through - except governance-mode retention, with
x-amz-bypass-governance-retention: true. Object Lock explains both
modes.
Differences from Amazon S3
The table lists each place where STRG behaves differently, and what that means for a client.
| Aspect | Amazon S3 | STRG |
|---|---|---|
| Versioning | Depends on the bucket: off, enabled or suspended | Always on. A delete without versionId writes a delete marker and removes nothing, so deleting the marker undoes it |
| Permissions | s3:DeleteObject, plus s3:DeleteObjectVersion for a version | Write objects without versionId; Delete object versions instead with one |
| Conditional deletes | If-Match supported; size and time conditions on directory buckets | 501 NotImplemented, and nothing is deleted |
| MFA Delete | x-amz-mfa | 501 NotImplemented |
x-amz-expected-bucket-owner | Checked against the bucket owner | Welcome, with nothing to check |
| Bucket in another region | 301 redirect with x-amz-bucket-region | 404 NoSuchBucket. A bucket is reached through its own regional endpoint |
Keys with . or .. segments | Allowed | 400 InvalidURI. DeleteObjects deletes such a key |
Examples
Deleting photos/2024/cat.jpg, which writes a delete marker:
- AWS CLI
- Python (boto3)
- JavaScript (AWS SDK v3)
aws s3api delete-object \
--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.delete_object(Bucket="my-bucket", Key="photos/2024/cat.jpg")
print(response.get("DeleteMarker"), response.get("VersionId"))
import { DeleteObjectCommand, 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 DeleteObjectCommand({
Bucket: "my-bucket",
Key: "photos/2024/cat.jpg",
}),
);
console.log(response.DeleteMarker, response.VersionId);
Permanently deleting one version, with its version ID - from
ListObjectVersions - in VERSION_ID. Naming a delete marker's
version ID restores the object:
- AWS CLI
- Python (boto3)
- JavaScript (AWS SDK v3)
aws s3api delete-object \
--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",
)
s3.delete_object(
Bucket="my-bucket",
Key="photos/2024/cat.jpg",
VersionId=os.environ["VERSION_ID"],
)
import { DeleteObjectCommand, S3Client } from "@aws-sdk/client-s3";
const client = new S3Client({
endpoint: "https://s3.eu-central-1.strg.com",
region: "eu-central-1",
});
await client.send(
new DeleteObjectCommand({
Bucket: "my-bucket",
Key: "photos/2024/cat.jpg",
VersionId: process.env.VERSION_ID,
}),
);
A version locked in governance mode is deleted the same way with --bypass-governance-retention
added (BypassGovernanceRetention=True in boto3, BypassGovernanceRetention: true in the
JavaScript SDK). The access key then needs Bypass governance retention as well as Delete
object versions.