Conditional Operations (preconditions) | Tigris Object Storage Documentation

On this page

Tigris supports conditional operations through standard HTTP precondition headers. These headers let you execute read or write operations only when specific conditions are met, for example, writing an object only if it hasn't been modified since you last read it.

Conditional operations are commonly used to implement optimistic concurrency control: the client reads an object, captures its ETag or last-modified timestamp, performs some computation, and writes the result back only if the object hasn't changed in the meantime.

Supported Condition Headers

ETag-based conditions

Header Behavior
If-Match Request proceeds only if the object's ETag matches the provided value. Returns 412 Precondition Failed otherwise.
If-None-Match Request proceeds only if the object's ETag does not match. Use If-None-Match: "*" to write only if the object does not already exist. Returns 304 Not Modified on a matching GET, or 412 Precondition Failed on a matching PUT.

Date-based conditions

Header Behavior
If-Modified-Since Request proceeds only if the object was modified after the provided date (RFC 1123 format). Returns 304 Not Modified otherwise.
If-Unmodified-Since Request proceeds only if the object was not modified after the provided date. Returns 412 Precondition Failed otherwise.

Combining conditions

Multiple condition headers can be specified in a single request. The request proceeds only if all conditions are met. If any condition fails, the request is rejected with the appropriate error status code.

Consistency and Conditional Operations

Conditional operations always evaluate against the latest state of the object within the consistency model defined by your bucket's location type.

If your workload requires conditional writes from multiple regions on the same objects, we recommend using a Multi-region or Single-region bucket. This guarantees that preconditions are always evaluated against the globally consistent latest state, without any additional configuration.

Conditional copy

Tigris supports extra set of conditional headers for source object in CopyObject operation.

Header Behavior
X-Amz-Copy-Source-If-Match Request proceeds only if the source object's ETag matches the provided value. Returns 412 Precondition Failed otherwise.
X-Amz-Copy-Source-If-None-Match Request proceeds only if the source object's ETag does not match the provided value. Returns 412 Precondition Failed otherwise.
X-Amz-Copy-Source-If-Modified-Since Request proceeds only if the source object was modified after the provided date (RFC 1123 format). Returns 412 Precondition Failed otherwise.
X-Amz-Copy-Source-If-Unmodified-Since Request proceeds only if the source object was not modified after the provided date. Returns 412 Precondition Failed otherwise.

Use Cases

Create-if-not-exists

Upload an object only if it doesn't already exist:

PUT /my-object HTTP/1.1

If-None-Match: "*"

If the object already exists, the request fails with 412 Precondition Failed.

Compare-and-swap (optimistic concurrency)

Read an object, modify it, and write it back only if no one else has changed it:

  1. Read the object and capture its ETag from the response.
  2. Write the modified object with If-Match set to the captured ETag.
PUT /my-object HTTP/1.1

If-Match: "etag-from-previous-read"

If the object was modified between the read and the write, the request fails with 412 Precondition Failed. The client can then re-read and retry.

Conditional GET (cache validation)

Fetch an object only if it has changed since you last retrieved it:

GET /my-object HTTP/1.1

If-None-Match: "etag-from-cached-copy"

If the object hasn't changed, the response is 304 Not Modified with no body.

Conditional copy

Copy object only if it was modified since a given date:

PUT /destination-bucket/object-copy HTTP/1.1

X-Amz-Copy-Source: /source-bucket/source-object

X-Amz-Copy-Source-If-Modified-Since: Mon, 01 Jan 2024 00:00:00 GMT

Error Responses

Status Code Meaning
304 Not Modified The condition indicates the object hasn't changed (GET requests).
412 Precondition Failed One or more conditions were not met (PUT, DELETE, or GET requests).