S3 Conditional Operations
SeaweedFS supports AWS S3-compatible conditional headers for safe concurrent access patterns, optimistic locking, and efficient conditional operations.
The conditional check and the write are atomic — cluster-wide. The
precondition is evaluated against the live object and the write is applied
under the same lock, on the filer that owns the key in the cluster's hash
ring. Two clients racing an If-Match update never both succeed, regardless
of which filer each one talks to. See
Filer Operation Serialization for the underlying primitive
(ObjectTransaction) and how it stays correct across filer restarts and
ring changes.
Supported Conditional Headers
These conditions act on the target object (the object being read or
written). All four are supported on GET, HEAD, PUT, POST
(CompleteMultipartUpload), and COPY. DELETE supports only If-Match.
| Header | Type | Applies to | Special values |
|---|---|---|---|
If-Match |
ETag | GET, HEAD, PUT, POST, COPY, DELETE | * matches any existing object; comma-separated ETag list is honored |
If-None-Match |
ETag | GET, HEAD, PUT, POST, COPY | * matches only when the object does not exist (compare-and-create); comma-separated ETag list is honored |
If-Modified-Since |
RFC 1123 date | GET, HEAD, PUT, POST, COPY | — |
If-Unmodified-Since |
RFC 1123 date | GET, HEAD, PUT, POST, COPY | — |
Copy-source conditionals
CopyObject and UploadPartCopy accept a second set of headers that
condition on the source object. They are independent of the four
standard headers above (which condition on the destination), so a single
copy request can carry conditions for both ends.
| Header | Type |
|---|---|
x-amz-copy-source-if-match |
ETag |
x-amz-copy-source-if-none-match |
ETag |
x-amz-copy-source-if-modified-since |
RFC 1123 date |
x-amz-copy-source-if-unmodified-since |
RFC 1123 date |
Evaluation order
Per RFC 7232 §6 and AWS S3, the conditions are evaluated in this order; later conditions are skipped when an earlier one is present:
If-MatchIf-Unmodified-Since— ignored ifIf-Matchis present (RFC 7232 §3.4)If-None-MatchIf-Modified-Since— ignored ifIf-None-Matchis present (RFC 7232 §3.3)
Not supported
If-Range. ARangerequest withoutIf-Rangeworks normally; there is no header to fall back to a full-object response when the source has changed.
HTTP Examples
Conditional GET (Caching)
# First, get the object and note its ETag
curl -I "http://localhost:8333/mybucket/myfile.txt"
# Response: ETag: "d41d8cd98f00b204e9800998ecf8427e"
# Conditional GET - only download if object changed
curl -H "If-None-Match: \"d41d8cd98f00b204e9800998ecf8427e\"" \
"http://localhost:8333/mybucket/myfile.txt"
Conditional PUT (Optimistic Locking)
# Safe update - only modify if object hasn't changed
curl -X PUT -H "If-Match: \"d41d8cd98f00b204e9800998ecf8427e\"" \
-H "Content-Type: text/plain" \
--data "Updated content" \
"http://localhost:8333/mybucket/myfile.txt"
# Prevent overwrites - only create if object doesn't exist
curl -X PUT -H "If-None-Match: *" \
-H "Content-Type: text/plain" \
--data "New file content" \
"http://localhost:8333/mybucket/newfile.txt"
If-Modified-Since
# Only download if modified after specific date
curl -H "If-Modified-Since: Wed, 15 Jan 2024 10:00:00 GMT" \
"http://localhost:8333/mybucket/log-file.txt"
If-Unmodified-Since
# Update only if not modified since last read
curl -X PUT \
-H "If-Unmodified-Since: Wed, 15 Jan 2024 10:00:00 GMT" \
-H "Content-Type: text/plain" \
--data "Updated content" \
"http://localhost:8333/mybucket/document.txt"
Copy Operations
# Copy only if source object hasn't changed
curl -X PUT \
-H "x-amz-copy-source: /source-bucket/source-file.txt" \
-H "x-amz-copy-source-if-match: \"source-etag\"" \
"http://localhost:8333/dest-bucket/dest-file.txt"
# Same copy, but also refuse to overwrite the destination
curl -X PUT \
-H "x-amz-copy-source: /source-bucket/source-file.txt" \
-H "x-amz-copy-source-if-match: \"source-etag\"" \
-H "If-None-Match: *" \
"http://localhost:8333/dest-bucket/dest-file.txt"
Conditional DELETE
# Delete only if the object's ETag still matches what we read
curl -X DELETE \
-H "If-Match: \"d41d8cd98f00b204e9800998ecf8427e\"" \
"http://localhost:8333/mybucket/myfile.txt"
DELETE supports If-Match only; the other three conditional headers are
ignored on DELETE per the AWS S3 spec.
HTTP Status Codes
| Status Code | When | Meaning |
|---|---|---|
| 200 OK | All conditions met | Operation succeeded normally |
| 304 Not Modified | GET/HEAD with If-None-Match match, or If-Modified-Since not exceeded |
Object unchanged; response carries the ETag header but no body |
| 400 Invalid Request | If-Modified-Since or If-Unmodified-Since is not a valid RFC 1123 date |
Header is malformed |
| 412 Precondition Failed | Any other failed condition (all writes; GET/HEAD with If-Match mismatch or If-Unmodified-Since exceeded) |
Operation blocked by condition |
Atomicity and concurrency
The contract is the same as AWS S3: a successful PUT with a precondition
header means the precondition held at the moment the write was applied,
not merely at some earlier read. The two cases worth calling out:
If-None-Match: "*"(compare-and-create). At most one of any number of concurrentPUTs for the same key succeeds; the rest return412 Precondition Failed. Use this as a primitive for distributed leader election, exclusive file creation, or idempotent uploads.If-Match: "<etag>"(optimistic concurrency). A read-modify-write cycle that fails with412means another writer changed the object between your read and your write. Retry against the new ETag.
How it stays correct across a multi-filer cluster:
- The S3 gateway forwards each write to a filer. That filer issues a
single
ObjectTransactionRPC describing the precondition plus the mutations (e.g. write the object + flip the version pointer + delete the prior null-version entry). - The transaction is routed by key to the owner filer for that object — the same filer for every concurrent writer of the same key, regardless of which gateway or filer they entered through.
- The owner takes an exclusive per-path lock for the key's lifetime of the transaction, evaluates the precondition against the current metadata, and applies the mutations under that lock. The whole sequence is one RPC; there is no caller-held distributed lock that can leak on a slow or crashed client.
- During filer membership changes, the same routing primitive applies a cooling-window dual-read and a warm-up period so a new owner never serves a write whose precondition it cannot yet verify. The precondition guarantee survives ring changes.
The detailed mechanism is in Filer Operation Serialization. The same primitive also powers cross-mount POSIX advisory locks; see Distributed POSIX Locks.
Related Documentation
Introduction
- Quick Start with weed mini
- Simplest S3 Bucket and User Setup
- Components
- Getting Started
- Production Setup
- A typical step‐by‐step example
- Benchmarks
- FAQ
- Applications
API
Configuration
- Replication
- Store file with a Time To Live
- Failover Master Server
- Erasure coding for warm storage
- EC Bitrot Detection
- Server Startup via Systemd
- Environment Variables
Filer
- Filer Setup
- Directories and Files
- File Operations Quick Reference
- Data Structure for Large Files
- Filer Data Encryption
- Filer Commands and Operations
- Filer JWT Use
- TUS Resumable Uploads
Filer Stores
- Filer Cassandra Setup
- Filer Redis Setup
- Super Large Directories
- Path-Specific Filer Store
- Choosing a Filer Store
- Customize Filer Store
Management
Advanced Filer Configurations
- Migrate to Filer Store
- Add New Filer Store
- Filer Store Replication
- Filer Active Active cross cluster continuous synchronization
- Filer as a Key-Large-Value Store
- Path Specific Configuration
- Filer Change Data Capture
- Filer Operation Serialization
FUSE Mount
- FIO benchmark
- fstab and systemd mount
- POSIX Compliance
- Distributed POSIX Locks
- P2P reading in weed mount
WebDAV
SFTP Server
Cloud Drive
- Cloud Drive Benefits
- Cloud Drive Architecture
- Configure Remote Storage
- Mount Remote Storage
- Cache Remote Storage
- Cloud Drive Quick Setup
- Gateway to Remote Object Storage
AWS S3 API
- Amazon S3 API
- Supported APIs vs Minio
- S3 Lifecycle
- S3 Lifecycle vs Volume TTL
- S3 Conditional Operations
- S3 CORS
- S3 Object Lock and Retention
- S3 Object Versioning
- S3 API Benchmark
- S3 API FAQ
- S3 Bucket Quota
- S3 Rate Limiting
- S3 API Audit log
- S3 Nginx Proxy
- Docker Compose for S3
S3 Table Bucket
- S3 Table Bucket
- S3 Table Bucket Commands
- S3 Tables Security
- SeaweedFS Iceberg Catalog
- Iceberg Table Maintenance
Iceberg Integrations
- Spark Iceberg Integration
- Trino Iceberg Integration
- Dremio Iceberg Integration
- DuckDB Iceberg Integration
- Doris Iceberg Integration
- RisingWave Iceberg Integration
- Lakekeeper Iceberg Integration
S3 Authentication & IAM
- S3 Configuration - Start Here
- S3 Credentials (
-s3.config) - OIDC Integration (
-s3.iam.config) - Kubernetes ServiceAccount Authentication (IRSA-style)
- S3 Policy Variables
- S3 Policy Conditions
- S3 Bucket Policies
- Amazon IAM API
- AWS IAM CLI
- weed shell - Shell IAM Commands
Server-Side Encryption
S3 Client Tools
- AWS CLI with SeaweedFS
- s3cmd with SeaweedFS
- rclone with SeaweedFS
- restic with SeaweedFS
- nodejs with Seaweed S3
Machine Learning
HDFS
- Hadoop Compatible File System
- run Spark on SeaweedFS
- run HBase on SeaweedFS
- run Presto on SeaweedFS
- Hadoop Benchmark
- HDFS via S3 connector
Replication and Backup
- Async Replication to another Filer [Deprecated]
- Async Backup
- Async Filer Metadata Backup
- Async Replication to Cloud [Deprecated]
- Kubernetes Backups and Recovery with K8up
Metadata Change Events
Messaging
- Structured Data Lake with SMQ and SQL
- Seaweed Message Queue
- SQL Queries on Message Queue
- SQL Quick Reference
- PostgreSQL-compatible Server weed db
- Pub-Sub to SMQ to SQL
- Kafka to Kafka Gateway to SMQ to SQL
Use Cases
Operations
- System Metrics
- weed shell
- Data Backup
- Deployment to Kubernetes and Minikube
- Deployment with seaweed-up
Rust Volume Server
Advanced
- Large File Handling
- Optimization
- Optimization for Many Small Buckets
- Volume Management
- Tiered Storage
- Cloud Tier
- Cloud Monitoring
- Load Command Line Options from a file
- SRV Service Discovery
- Volume Files Structure
Security
- Security Overview
- Security Configuration
- Cryptography and FIPS Compliance
- Run Blob Storage on Public Internet