> ## Documentation Index
> Fetch the complete documentation index at: https://bunny.net/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# S3

Bunny Storage supports an S3-compatible API, allowing you to use familiar S3 tools, libraries, and workflows with your storage zones. Use existing S3 tools and scripts, leverage popular S3 libraries across all programming languages, migrate from AWS S3 with minimal code changes, and work with S3 GUI tools.

> [!NOTE]
>
> S3 compatibility is currently in public preview. Currently, S3 compatibility can only be enabled when creating a new storage zone and cannot be enabled on an existing storage zone. Support for enabling S3 compatibility on existing storage zones is currently in development.

## Creating a storage zone with S3 compatibility

To create an S3-compatible storage zone:

1. Navigate to **Storage** → **Add Storage Zone**
2. Enter a name (minimum 4 characters, letters, numbers, and dashes only)
3. Enable the **S3 Compatibility** option
4. Select your preferred storage tier
5. Choose your region
6. Configure replication
7. Confirm and **Add Storage Zone**

## Quickstart

Once you've created your S3-compatible storage zone, you're ready to connect.

### Authentication and credentials

The credentials you need to connect via S3 are located in the **Access** tab:

* **Access Key ID**: Your Storage Zone name (bucket name)
* **Secret Access Key**: Your Storage Zone Password
* **Endpoint URL**: `https://[region]-s3.storage.bunnycdn.com`
* **Region**: `de` (Frankfurt), `ny` (New York), `sg` (Singapore), `uk` (London), \
  `se` (Stockholm), `la` (Los angeles),`jh` (Johannesburg) & `syd` (Sydney)

> [!NOTE]
>
> Bunny Storage supports both path-style URLs (e.g., `https://[region]-s3.storage.bunnycdn.com/bucket-name/key`) and virtual hosted-style URLs (e.g., `https://bucket-name.[region]-s3.storage.bunnycdn.com/key`).

### Content Type Detection

When uploading objects, Content-Type is determined in the following order:

1. **Content-Type header** - If provided in the request
2. **File extension detection** - Automatic detection based on file extension
3. **Default fallback** - `binary/octet-stream` for unknown types

### Checksum Validation

SHA256 checksum validation is available using the `x-amz-checksum-sha256` header (Base64 encoded).

### Presigned URL Validation

Presigned URLs require authentication. For publicly available presigned URLs fronted by CDN please use [bunny.net](http://bunny.net) CDN by adding a pullzone to your storage zone.

| Parameter | Description |
| - | - |
| `X-Amz-Algorithm` | Signing algorithm type (AWS4-HMAC-SHA256) |
| `X-Amz-Credential` | Access key + date + region + service + aws4\_request |
| `X-Amz-Date` | Timestamp URL signed in 'YYYYMMDDTHHMMSSZ' format |
| `X-Amz-Expires` | Validity duration in seconds from X-Amz-Date (default 1hour) |
| `X-Amz-SignedHeaders` | Headers included in the signature |
| `X-Amz-Signature` | The HMAC-SHA256 signature |

**Presigned URL example (1hour):**\
https\://\[region]-s3.storage.bunnycdn.com/bucket-name/path/to/object/?X-Amz-Algorithm=AWS4-HMAC-SHA256\&X-Amz-Credential=\[AccessKeyID+Date+region+servicerequest]\&X-Amz-Date=20260320T160912Z\&X-Amz-Expires=3600\&X-Amz-SignedHeaders=host\&X-Amz-Signature=\[HMAC-SHA256Signature]/

> [!NOTE]
>
> **Presigned URL cache:** Presigned URLs are cached and the cache validates signatures for cached objects. Currently objects up to 256 MB are cached, and only if they are accessed at least twice.

### Object metadata

You can attach metadata to an object when you upload it with `PutObject` or `CreateMultipartUpload`. It is stored with the object and returned on every `GetObject` and `HeadObject` response.

* **Custom metadata**: any `x-amz-meta-*` header. Keys are stored lowercase, as on AWS.
* **System metadata**: `Cache-Control`, `Content-Disposition`, `Content-Encoding`, `Content-Language`, `Expires`, and `x-amz-website-redirect-location`.

Each set is limited to **2 KB** of combined key and value bytes. A request over the limit is rejected with `400 MetadataTooLarge`.

`CopyObject` keeps the source object's metadata by default. Send `x-amz-metadata-directive: REPLACE` to store the metadata from the copy request instead. The website redirect location is never copied and must be set on the copy request explicitly.

> [!WARNING]
>
> Metadata keys that contain an underscore, such as `x-amz-meta-my_key, are silently dropped and the upload still succeeds. Use hyphens `x-amz-meta-my-key\`.

> [!NOTE]
>
> Metadata is only available over S3. CDN pull zones do not yet use stored metadata, so headers such as `Cache-Control` and `Content-Disposition` are not sent with CDN responses. Configure caching and download behavior on the CDN pull zone instead. Overwriting an object through the HTTP API, FTP, SFTP, or the dashboard clears its S3 metadata.

`GetObject` and `HeadObject` also honor the `response-content-type`, `response-cache-control`, `response-content-disposition`, `response-content-encoding`, `response-content-language`, and `response-expires` query parameters, so a presigned URL can force a download filename or cache policy.

#### Adding metadata to existing objects

Objects uploaded before metadata support, or through a non-S3 protocol, have no S3 metadata. To add it, copy the object onto itself with `x-amz-metadata-directive: REPLACE`:

```bash theme={null}
aws s3api copy-object --bucket bucket-name \
  --key path/to/object \
  --copy-source bucket-name/path/to/object \
  --metadata-directive REPLACE \
  --metadata author=jane,project=demo \
  --cache-control "max-age=86400" \
  --content-type "image/png" \
  --profile bunny \
  --endpoint-url https://[region]-s3.storage.bunnycdn.com
```

> [!WARNING]
>
> `REPLACE` replaces all of the object's metadata with the headers on the copy request. Include every header you want to keep, and always send `Content-Type` explicitly so the object keeps the correct type.

#### Uploading with metadata through a presigned URL

To upload with metadata through a presigned `PUT` URL, include the `x-amz-meta-*` and system metadata headers when you generate the URL with your SDK, so they become part of the signature. The client must then send exactly the same headers and values with the upload. A missing or changed header fails with `403 SignatureDoesNotMatch`.

### Bulk delete

`DeleteObjects` deletes up to **1,000 keys** in a single request. Each key is reported individually in the response, so one failed key does not abort the batch. Deleting a key that does not exist counts as a success, and duplicate keys collapse to a single result entry.

* The request must carry a `Content-MD5` or `x-amz-checksum-*` header, as on AWS. Supported algorithms are CRC32, CRC32C, CRC64NVME, SHA1, and SHA256. The AWS CLI and SDKs add one automatically.
* Entries with a `VersionId` are rejected per key, as versioning is not yet supported.
* A folder key only removes the empty folder marker. Its contents stay in place.
* If the request returns `503 SlowDown`, retry the operation after the `Retry-After` interval.

## Example

### AWS CLI

> [!NOTE]
>
> You must use `--endpoint-url https://[region]-s3.storage.bunnycdn.com` with each command or set up an [AWS CLI profile](https://docs.aws.amazon.com/cli/v1/userguide/cli-configure-files.html#cli-configure-files-methods) with the endpoint configured.

```bash theme={null}
# Configure AWS CLI with your storage zone credentials
aws configure --profile bunny
# AWS Access Key ID: your-storage-zone-name
# AWS Secret Access Key: your-storage-password
# Default region name: your-region (e.g., de, ny, sg)
# Default output format: json

# Upload an object (PUT Object)
aws s3 cp /path/to/local/file s3://bucket-name/path/to/destination/ \
  --profile bunny \
  --endpoint-url https://[region]-s3.storage.bunnycdn.com

# Download an object (GET Object)
aws s3 cp s3://bucket-name/path/to/object /path/to/local/destination/ \
  --profile bunny \
  --endpoint-url https://[region]-s3.storage.bunnycdn.com

# List objects (LIST Objects)
aws s3 ls s3://bucket-name/ --recursive \
  --profile bunny \
  --endpoint-url https://[region]-s3.storage.bunnycdn.com

# Delete an object (DELETE Object)
aws s3 rm s3://bucket-name/path/to/object \
  --profile bunny \
  --endpoint-url https://[region]-s3.storage.bunnycdn.com

# Delete multiple objects in one request (DELETE Objects)
aws s3api delete-objects --bucket bucket-name \
  --delete '{"Objects":[{"Key":"path/to/first"},{"Key":"path/to/second"}],"Quiet":false}' \
  --profile bunny \
  --endpoint-url https://[region]-s3.storage.bunnycdn.com

# Upload an object with custom metadata and cache headers
aws s3 cp /path/to/local/file s3://bucket-name/path/to/destination/ \
  --metadata author=jane,project=demo \
  --cache-control "max-age=3600" \
  --profile bunny \
  --endpoint-url https://[region]-s3.storage.bunnycdn.com

# Copy object (COPY Object)
aws s3 cp s3://bucket-name/source/object s3://bucket-name/destination/object \
  --profile bunny \
  --endpoint-url https://[region]-s3.storage.bunnycdn.com

# Get object metadata (HEAD Object)
aws s3api head-object --bucket bucket-name --key path/to/object \
  --profile bunny \
  --endpoint-url https://[region]-s3.storage.bunnycdn.com

# Sync a directory
aws s3 sync ./local-dir s3://bucket-name/remote-dir/ \
  --profile bunny \
  --endpoint-url https://[region]-s3.storage.bunnycdn.com

# Generate a pre-signed URL
aws s3 presign s3://bucket-name/path/to/object \
  --profile bunny \
  --endpoint-url https://[region]-s3.storage.bunnycdn.com \
  --expires-in 86400
```

### rclone

You can use rclone with Bunny Storage:

```bash theme={null}
# Configure rclone
rclone config create bunnycdn s3 \
  provider=Other \
  access_key_id=your-storage-zone-name \
  secret_access_key=your-storage-password \
  endpoint=https://[region]-s3.storage.bunnycdn.com

# Upload an object (PUT Object)
rclone copy /path/to/local/file bunnycdn:bucket-name/path/to/destination/

# Download an object (GET Object)
rclone copy bunnycdn:bucket-name/path/to/object /path/to/local/destination/

# List objects (LIST Objects)
rclone ls bunnycdn:bucket-name/
rclone lsd bunnycdn:bucket-name/  # List directories only
rclone lsl bunnycdn:bucket-name/  # List with size and modification time

# Delete an object (DELETE Object)
rclone delete bunnycdn:bucket-name/path/to/object

# Delete a directory
rclone purge bunnycdn:bucket-name/path/to/directory/

# Copy object within bucket (COPY Object)
rclone copy bunnycdn:bucket-name/source/object bunnycdn:bucket-name/destination/

# Get object info (HEAD Object)
rclone lsl bunnycdn:bucket-name/path/to/object

# Sync a directory
rclone sync ./local-dir bunnycdn:bucket-name/remote-dir/

# Move objects
rclone move /path/to/local/file bunnycdn:bucket-name/destination/

# Copy object from URL
rclone copyurl URL bunnycdn:bucket-name/destination/
```

## Supported S3 operations

Bunny Storage provides comprehensive S3 API compatibility for all your storage needs.

### Object operations

* **PUT Object**: Create and update objects
* **GET Object**: Read objects (range requests supported)
* **DELETE Object**: Delete a single object
* **DELETE Objects**: Delete up to 1,000 objects in one request
* **COPY Object**: Copy objects between locations
* **HEAD Object**: Get object metadata, including custom `x-amz-meta-*` headers
* **PRESIGN Object**: Generate object URL expiry time (Set in seconds - default 1 hour)

### Directory listing

* **LIST Objects**: List objects (V1 and V2)
* List with prefix filtering
* Paginated results
* Directory-style navigation
* Common prefixes support

### Multipart upload operations

Bunny Storage provides full support for S3 multipart uploads, enabling efficient upload of large objects. Recommended for objects over 100MB.

| API Name | Features |
| - | - |
| ✅ [`CreateMultipartUpload`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateMultipartUpload.html) | ✅ Multipart session creation ✅ Returns UploadId ✅ System Metadata:     ✅ Content-Type (with automatic detection from file extension)     ✅ Content-Type stored in session for final object ✅ Custom metadata (x-amz-meta-\*, 2 KB limit) ✅ Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Expires (2 KB limit) ✅ Automatic replication session creation ❌ Storage class selection ❌ SSE/SSE-C encryption ❌ Object tagging ❌ Object locking ❌ ACL headers |
| ✅ [`UploadPart`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPart.html) | ✅ Part upload (up to 10,000 parts) ✅ Returns ETag (part checksum) ✅ Automatic replication of parts ✅ Content-MD5 validation ❌ SSE/SSE-C encryption |
| ✅ [`UploadPartCopy`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html) | ✅ Copy within same storage zone ✅ Part size up to 5 GB ✅ Range copy (source object must be greater than 5 MB) ✅ Supported headers:     ✅ x-amz-copy-source     ✅ x-amz-copy-source-range (optional, format: bytes=first-last) ✅ Conditional source headers:     ✅ x-amz-copy-source-if-match     ✅ x-amz-copy-source-if-modified-since     ✅ x-amz-copy-source-if-none-match     ✅ x-amz-copy-source-if-unmodified-since ❌ Cross-zone copying ❌ Server-side encryption ❌ Bucket-owner verification ❌ Requester payer ❌ ACL grants |
| ✅ [`ListParts`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListParts.html) | ✅ Query Parameters:     ✅ max-parts (default 1000)     ✅ part-number-marker ✅ Returns part ETag and size ✅ Pagination support ✅ IsTruncated flag |
| ✅ [`CompleteMultipartUpload`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CompleteMultipartUpload.html) | ✅ Finalizes multipart upload ✅ Validates all parts present ✅ Validates part ETags ✅ Creates final object with combined checksum ✅ Final checksum format: `MD5(part1+part2+...)-{partCount}` ✅ Applies Content-Type, custom metadata, and system metadata from session ✅ Automatic replication of completed object ✅ Cleanup of part files ✅ Returns ETag, Location, Bucket, Key ❌ Checksums in response |
| ✅ [`AbortMultipartUpload`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_AbortMultipartUpload.html) | ✅ Cancels multipart upload ✅ Deletes all uploaded parts |
| ✅ [`ListMultipartUploads`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListMultipartUploads.html) | ✅ Query Parameters:     ✅ prefix     ✅ delimiter     ✅ key-marker     ✅ upload-id-marker     ✅ max-uploads (default 1000) ✅ Pagination support ✅ Returns UploadId, Key, Initiated date |

### S3 API compatibility matrix

Below is a detailed list of implemented object-level operations with their supported features:

| API Name | Features |
| - | - |
| ✅ [`HeadObject`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_HeadObject.html) | ✅ Basic metadata retrieval ✅ Response headers:     ✅ Content-Type     ✅ Content-Length     ✅ Last-Modified     ✅ ETag     ✅ x-amz-meta-\* (custom metadata)     ✅ Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Expires ✅ response-\* header overrides (response-content-type, response-content-disposition, etc.) ✅ Conditional Operations:     ✅ If-Match     ✅ If-Modified-Since     ✅ If-None-Match     ✅ If-Unmodified-Since ❌ Range queries ❌ SSE-C encryption headers |
| ✅ [`GetObject`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) | ✅ Full object download ✅ Response headers:     ✅ Content-Type     ✅ Content-Length     ✅ Last-Modified     ✅ ETag     ✅ x-amz-meta-\* (custom metadata)     ✅ Cache-Control, Content-Disposition, Content-Encoding, Content-Language, Expires ✅ response-\* header overrides (response-content-type, response-content-disposition, etc.) ✅ Range requests (byte ranges) ✅ Multipart object download ✅ Conditional Operations:     ✅ If-Match     ✅ If-Modified-Since     ✅ If-None-Match     ✅ If-Unmodified-Since ❌ SSE-C encryption ❌ Versioning support |
| ✅ [`PutObject`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObject.html) | ✅ Object upload ✅ System Metadata:     ✅ Content-Type (with automatic detection)     ✅ Content-Length     ✅ Cache-Control     ✅ Content-Disposition     ✅ Content-Encoding     ✅ Content-Language     ✅ Expires     ✅ x-amz-website-redirect-location ✅ Custom metadata:     ✅ x-amz-meta-\* (2 KB limit, keys stored lowercase) ✅ Checksum validation:     ✅ x-amz-checksum-sha256 (Base64 encoded) ✅ Automatic replication to configured zones ❌ Storage Class selection ❌ SSE encryption ❌ SSE-C encryption ❌ Object tagging:     ❌ x-amz-tagging ❌ Object locking ❌ ACL headers:     ❌ x-amz-acl     ❌ x-amz-grant-\* |
| ✅ [`DeleteObject`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObject.html) | ✅ Single object deletion ❌ Multi-factor authentication ❌ Object Locking ❌ Request Payer |
| ✅ [`DeleteObjects`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html) | ✅ Up to 1,000 keys per request ✅ Per-key success and error reporting ✅ Quiet mode ✅ Body integrity check (Content-MD5 or an x-amz-checksum-\* header is required) ✅ CRC32, CRC32C, CRC64NVME, SHA1, and SHA256 checksums ✅ Conditional entries (ETag, LastModifiedTime, Size) ❌ VersionId entries (rejected per key) ❌ Multi-factor authentication ❌ Object Locking |
| ✅ [`CopyObject`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html) | ✅ Object copy within same storage zone ✅ Object size up to 5 GB ✅ Response fields:     ✅ LastModified     ✅ ChecksumSHA256 (Base64 encoded) ✅ Source object checksum validation ✅ Content-Type preservation ✅ ETag in response ✅ Metadata directive:     ✅ x-amz-metadata-directive (COPY keeps the source metadata, REPLACE uses the request headers) ✅ Custom and system metadata copied or replaced ✅ Conditional copy operations:     ✅ x-amz-copy-source-if-match     ✅ x-amz-copy-source-if-modified-since     ✅ x-amz-copy-source-if-none-match     ✅ x-amz-copy-source-if-unmodified-since ❌ Cross-zone copying ❌ Storage class selection ❌ SSE/SSE-C encryption ❌ Tagging |
| ✅ [`ListObjects`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html) | ✅ Query Parameters:     ✅ delimiter     ✅ encoding-type     ✅ marker     ✅ max-keys     ✅ prefix ✅ Common prefix support |
| ✅ [`ListObjectsV2`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html) | ✅ Query Parameters:     ✅ prefix     ✅ delimiter     ✅ max-keys     ✅ continuation-token     ✅ start-after ✅ Common prefix support ❌ fetch-owner |
| ✅ `Presign` | ✅ Configuration:     ✅ expires-in     ✅ Signing algorithm AWS4-HMAC-SHA256 |

### Unsupported operations

> [accordion] View unsupported S3 operations
>
> The following S3 operations are not currently supported:
>
> | API Name | Feature |
> | - | - |
> | ❌ [GetObjectAcl](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAcl.html) | ❌ ACLs not supported |
> | ❌ [PutObjectAcl](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectAcl.html) | ❌ ACLs not supported |
> | ❌ [GetObjectTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectTagging.html) | ❌ Object tagging not supported |
> | ❌ [PutObjectTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectTagging.html) | ❌ Object tagging not supported |
> | ❌ [DeleteObjectTagging](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectTagging.html) | ❌ Object tagging not supported |
> | ❌ [GetObjectAttributes](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectAttributes.html) | ❌ Not implemented |
> | ❌ [GetObjectLegalHold](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectLegalHold.html) | ❌ Object locking not supported |
> | ❌ [PutObjectLegalHold](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectLegalHold.html) | ❌ Object locking not supported |
> | ❌ [GetObjectRetention](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectRetention.html) | ❌ Object retention not supported |
> | ❌ [PutObjectRetention](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectRetention.html) | ❌ Object retention not supported |
> | ❌ [SelectObjectContent](https://docs.aws.amazon.com/AmazonS3/latest/API/API_SelectObjectContent.html) | ❌ S3 Select not supported |
> | ❌ [RestoreObject](https://docs.aws.amazon.com/AmazonS3/latest/API/API_RestoreObject.html) | ❌ Glacier operations not supported |

## Limits

Be aware of the following limitations when using S3-compatible storage:

* 500 Max RPS rate (upload & download combined)
* 1Gbps Max bandwidth throughput

### Regional availability

S3-compatible storage zones support automatic multi-region replication. All operations including uploads, deletes, and multipart uploads are automatically replicated to your configured replication regions.

S3 compatibility is currently available in the following regions:

* Frankfurt (DE)
* New York (NY)
* Singapore (SG)
* London (UK)
* Stockholm (SE)
* Los Angeles (LA)
* Johannesburg (JH)
* Sydney (SYD)

Additional regions will be added in the future. Regions that do not yet support S3 have no `[region]-s3` endpoint, and requests to their storage host return `501 NotImplemented`.

> [!NOTE]
>
> S3 compatibility cannot be changed after storage zone creation.

### Known limitations

The following S3 features are limited by:

* **ACLs**: Access Control Lists are not supported
* **CORS Configuration**: CORS is not configurable — the S3 endpoint always responds with `Access-Control-Allow-Origin: *`. To control CORS, front the storage zone with a pull zone and configure it at the CDN level for file delivery.
* **Lifecycle Policies**: Automatic lifecycle transitions are not supported
* **Object Metadata**: Custom metadata (`x-amz-meta-*`) and system metadata (`Cache-Control` and similar) are each limited to 2 KB. Keys containing an underscore are silently dropped. Metadata is returned only on S3 requests and is not yet used by pull zones. Metadata is cleared when the object is overwritten through a non-S3 protocol
* **Bulk Delete**: Maximum 1,000 keys per `DeleteObjects` request. A folder key removes only the folder marker, not its contents
* **Multipart Limits**: Maximum 10,000 parts per upload
* **Multipart Session Expiry**: Sessions expire after 10 days
* **Object Tagging**: Object and bucket tagging is not supported
* **Presigned URLs**: Minimum time: 1 second | Maximum time: 7 days (604800 seconds)
* **Server-Side Encryption**: SSE/SSE-C encryption is not currently supported
* **Versioning**: Object versioning is not supported

## Error Codes

Bunny Storage returns standard S3 error codes:

> [!NOTE]
>
> Some error codes may differ from standard AWS S3 behavior. See the notes below for Bunny-specific details.

| Error Code | HTTP Status | Description |
| - | - | - |
| `NoSuchKey` | 404 | The specified file, folder, or multipart upload does not exist |
| `NoSuchBucket` | 404 | The specified storage zone does not exist |
| `SignatureDoesNotMatch` | 403 | The request signature does not match (usually an incorrect secret access key, or a presigned request whose headers differ from the ones that were signed) |
| `AccessDenied` | 403 | Missing or malformed `Authorization` header, or credentials that do not match the target storage zone |
| `PreconditionFailed` | 412 | A conditional header (`If-Match`, `If-Unmodified-Since`, `x-amz-copy-source-if-*`) did not hold |
| `BadDigest` | 400 | The supplied `x-amz-checksum-sha256` or `Content-MD5` does not match the uploaded data |
| `InvalidRequest` | 400 | Invalid request parameters or headers, including a `DeleteObjects` request without a `Content-MD5` or `x-amz-checksum-*` header |
| `MalformedXML` | 400 | The `DeleteObjects` request body is not valid XML, is empty, or lists more than 1,000 keys |
| `MetadataTooLarge` | 400 | The `x-amz-meta-*` headers, or the system metadata headers, exceed 2 KB |
| `NotImplemented` | 501 | The requested operation is not implemented, or S3 is not supported by the storage region — see [Regional availability](#regional-availability) |
| `InternalError` | 500 | Internal server error |
| `ServiceUnavailable` | 403 | S3 compatibility is not enabled for this storage zone |
| `SlowDown` | 503 | Rate limit exceeded. The response includes a `Retry-After` header (in seconds) — wait for that interval, then retry with exponential backoff. See [Limits](#limits) |

## Best Practices

1. [**Use an SDK**](https://docs.aws.amazon.com/AmazonS3/latest/API/sdk-general-information-section.html) to interact with the S3 api
2. **Enable Replication** for at least one additional region
3. **Implement retry logic** for transient failures, honouring the `Retry-After` header on `SlowDown` responses
4. **Use multipart uploads** for objects larger than 100MB
5. **Include Content-Type headers** when uploading, or rely on automatic detection
6. **Handle pagination properly** when listing objects or parts (max 1000 per request)
7. **Monitor multipart sessions** and abort abandoned uploads to free storage
8. **Set presigned URL expiry time** in seconds `--expires-in 3600` = 1 hour
9. **Read-only password support** use this secret access key for read-only access


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.