document the RenameObject S3 API

Chris Lu committed 2026-08-09 22:33:39 -07:00
1 parent 19d35555bf
commit 6881e4552c
3 files changed
+112 -1

No files matched your search

+2 -1
@@ -142,7 +142,7 @@ For IAM action names used in bucket policies (e.g., `s3:ListBucketMultipartUploa
| PutObjectTagging | Yes | |
| DeleteObjectTagging | Yes | |
| GetObjectTorrent | No | |
| RenameObject | No | |
| RenameObject | Yes | Atomic metadata-only move; unversioned buckets only. See [[S3 RenameObject]] |
| RestoreObject | No | |
| SelectObjectContent | No | |
| WriteGetObjectResponse | No | S3 Object Lambda |
@@ -218,6 +218,7 @@ To be consistent with AWS S3, SeaweedFS automatically cleans up empty folders as
**Features**
- [[S3 Conditional Operations]] — If-Match, If-None-Match, If-Modified-Since, If-Unmodified-Since
- [[S3 RenameObject]] — Atomic metadata-only object rename
- [[S3 CORS]] — Cross-Origin Resource Sharing
- [[S3 Bucket Quota]] — Storage quota management
- [[S3 Rate Limiting]] — Request rate limiting
+109
@@ -0,0 +1,109 @@
# S3 RenameObject
SeaweedFS supports the S3 `RenameObject` API: rename an object within a
bucket in one atomic, metadata-only operation. AWS offers this API only on
directory buckets (S3 Express One Zone); SeaweedFS provides it on regular
buckets.
Available since version 4.42.
## How It Works
The rename is executed by the filer as an atomic metadata move. The
object's data is never read or rewritten, so renaming a 1 TB object costs
the same as renaming a 1 KB one, and the ETag, tags, user metadata, and
encryption metadata all travel unchanged.
Both keys are write-locked for the duration of the operation, and all
precondition headers are evaluated under those locks, so a conditional
rename is atomic cluster-wide — the same guarantee as
[[S3 Conditional Operations]].
## Request
```
PUT /{bucket}/{destination-key}?renameObject
x-amz-rename-source: {source-key}
```
The `x-amz-rename-source` value can be a bare key (`old-name.txt`) or
bucket-qualified (`mybucket/old-name.txt`), with or without a leading
slash — AWS's own examples use both forms. The value is read as a literal
key first; only when no such object exists and the value starts with the
request's own bucket name is it re-read as `bucket/key`. Cross-bucket
renames are not supported: the source bucket is always the request's
bucket.
With the AWS CLI:
```bash
aws --endpoint-url http://localhost:8333 s3api rename-object \
--bucket mybucket \
--key new-name.txt \
--rename-source mybucket/old-name.txt
```
Or as a raw request:
```bash
curl -X PUT -H "x-amz-rename-source: old-name.txt" \
"http://localhost:8333/mybucket/new-name.txt?renameObject"
```
## Conditional Headers
Like `CopyObject`, a rename can carry conditions for both ends of the
operation independently.
The source is conditioned with rename-source headers:
| Header | Type |
|--------|------|
| `x-amz-rename-source-if-match` | ETag |
| `x-amz-rename-source-if-none-match` | ETag |
| `x-amz-rename-source-if-modified-since` | RFC 1123 date |
| `x-amz-rename-source-if-unmodified-since` | RFC 1123 date |
The destination is conditioned with the four standard headers
(`If-Match`, `If-None-Match`, `If-Modified-Since`,
`If-Unmodified-Since`). The most useful one: an existing destination
object is silently replaced, as with `PutObject`, so send
`If-None-Match: *` to make the rename fail with `PreconditionFailed`
instead of overwriting.
```bash
curl -X PUT \
-H "x-amz-rename-source: old-name.txt" \
-H "If-None-Match: *" \
"http://localhost:8333/mybucket/new-name.txt?renameObject"
```
## Restrictions
* **Unversioned buckets only.** A bucket with versioning enabled or
suspended — including any bucket with Object Lock, which implies
versioning — returns `501 NotImplemented`. This matches AWS, where
RenameObject exists only on directory buckets, which cannot be
versioned.
* **Objects only.** A key with a trailing slash names a directory, and
renaming one would move a whole subtree; both ends reject it. An object
whose key is also a prefix of other keys (a "directory object") cannot
be renamed either.
* **Source read + delete permission.** The caller needs write permission
on the destination (it is the request URL), plus read and delete
permission on the source, since the rename both reads the object and
removes its old key.
* **No idempotency replay.** `x-amz-client-token` is accepted — AWS SDKs
fill it in automatically — but retrying a rename that already succeeded
returns `NoSuchKey`, because the source is gone.
## Errors
| Condition | Error |
|---|---|
| Source object does not exist | `NoSuchKey` (404) |
| Bucket is versioned | `NotImplemented` (501) |
| Destination same as source | `InvalidRequest` (400) |
| Missing or empty `x-amz-rename-source` | `InvalidArgument` (400) |
| A directory exists at the destination key | `ExistingObjectIsDirectory` (409) |
| A precondition failed | `PreconditionFailed` (412) |
+1
@@ -95,6 +95,7 @@
* [[S3 CORS]]
* [[S3 Object Lock and Retention]]
* [[S3 Object Versioning]]
* [[S3 RenameObject]]
* [[S3 API Benchmark]]
* [[S3 API FAQ]]
* [[S3 Bucket Quota]]