From 74c00b746083793efb1a1b3a94eaad647a41ea50 Mon Sep 17 00:00:00 2001 From: helloimalastair Date: Fri, 23 Oct 2026 15:45:35 -0700 Subject: [PATCH 1/3] [R2] R2-5726: Document 409 status and precedence for ObjectLockedByBucketPolicy --- src/content/docs/r2/api/error-codes.mdx | 2 +- src/content/docs/r2/buckets/bucket-locks.mdx | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/content/docs/r2/api/error-codes.mdx b/src/content/docs/r2/api/error-codes.mdx index ec69ca19bae..b91a69a8ec3 100644 --- a/src/content/docs/r2/api/error-codes.mdx +++ b/src/content/docs/r2/api/error-codes.mdx @@ -63,7 +63,7 @@ For the **S3-compatible API**, errors are returned as XML in the response body: | 10020 | InvalidObjectName | 400 | Object key contains invalid characters or is too long. | Use valid UTF-8 characters. Maximum key length is 1024 bytes. | | 100100 | EntityTooLarge | 400 | Object exceeds maximum size (5 GiB for single upload, 5 TiB for multipart). | Use [multipart upload](/r2/objects/upload-objects/#multipart-upload) for objects larger than 5 GiB. Maximum object size is 5 TiB. | | 10012 | MetadataTooLarge | 400 | Custom metadata exceeds the 8,192 byte limit. | Reduce custom metadata size. Maximum is 8,192 bytes total for all custom metadata. | -| 10069 | ObjectLockedByBucketPolicy | 403 | Object is protected by a bucket lock rule and cannot be modified or deleted. | Wait for the retention period to expire. Refer to [bucket locks](/r2/buckets/bucket-locks/). | +| 10069 | ObjectLockedByBucketPolicy | 409 | Object is protected by a bucket lock rule and cannot be modified or deleted. If a conditional header would also fail, this error is returned instead of `PreconditionFailed`. | Wait for the retention period to expire. Refer to [bucket locks](/r2/buckets/bucket-locks/). | ### Upload and request errors diff --git a/src/content/docs/r2/buckets/bucket-locks.mdx b/src/content/docs/r2/buckets/bucket-locks.mdx index 9d9009e01e3..fee119d176b 100644 --- a/src/content/docs/r2/buckets/bucket-locks.mdx +++ b/src/content/docs/r2/buckets/bucket-locks.mdx @@ -150,5 +150,6 @@ If multiple rules apply to the same prefix or object key, the strictest (longest - Rules without prefix apply to all objects in the bucket. - Bucket locks protect both existing objects and objects created after the rule is enabled. They do not prevent new object creation. - Once a rule update succeeds, changes to protected objects are blocked from that point on. This includes overwrites, deletes, completing uploads that started earlier, and removal by lifecycle rules. +- A request blocked by a bucket lock rule fails with HTTP `409` and the `ObjectLockedByBucketPolicy` error code. The lock check runs before conditional headers such as `If-None-Match` or `If-Match` are evaluated, so a write that fails both checks returns `ObjectLockedByBucketPolicy`, not `PreconditionFailed` (`412`). In either case the existing object is not modified. - Bucket lock rules take precedence over [lifecycle rules](/r2/buckets/object-lifecycles/). For example, if a lifecycle rule attempts to delete an object at 30 days but a bucket lock rule requires it be retained for 90 days, the object will not be deleted until the 90-day requirement is met. - A bucket cannot be emptied while any bucket lock rules are configured. Remove all lock rules before [emptying a bucket](/r2/buckets/delete-buckets/#empty-a-bucket). Bucket lock rules also apply when [deleting folders](/r2/objects/delete-objects/) from the dashboard. From c0e93a0a562f20eb3c148fd9ced7362d255ca466 Mon Sep 17 00:00:00 2001 From: helloimalastair Date: Mon, 26 Oct 2026 11:01:42 -0700 Subject: [PATCH 2/3] clarify ObjectLockedByBucketPolicy status for batch deletes and CopyObject --- src/content/docs/r2/api/error-codes.mdx | 2 +- src/content/docs/r2/buckets/bucket-locks.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/content/docs/r2/api/error-codes.mdx b/src/content/docs/r2/api/error-codes.mdx index b91a69a8ec3..5115966ae1a 100644 --- a/src/content/docs/r2/api/error-codes.mdx +++ b/src/content/docs/r2/api/error-codes.mdx @@ -63,7 +63,7 @@ For the **S3-compatible API**, errors are returned as XML in the response body: | 10020 | InvalidObjectName | 400 | Object key contains invalid characters or is too long. | Use valid UTF-8 characters. Maximum key length is 1024 bytes. | | 100100 | EntityTooLarge | 400 | Object exceeds maximum size (5 GiB for single upload, 5 TiB for multipart). | Use [multipart upload](/r2/objects/upload-objects/#multipart-upload) for objects larger than 5 GiB. Maximum object size is 5 TiB. | | 10012 | MetadataTooLarge | 400 | Custom metadata exceeds the 8,192 byte limit. | Reduce custom metadata size. Maximum is 8,192 bytes total for all custom metadata. | -| 10069 | ObjectLockedByBucketPolicy | 409 | Object is protected by a bucket lock rule and cannot be modified or deleted. If a conditional header would also fail, this error is returned instead of `PreconditionFailed`. | Wait for the retention period to expire. Refer to [bucket locks](/r2/buckets/bucket-locks/). | +| 10069 | ObjectLockedByBucketPolicy | 409 | Object is protected by a bucket lock rule and cannot be modified or deleted. If a conditional header on the object being written would also fail, this error is returned instead of `PreconditionFailed`. `CopyObject` source conditions (`x-amz-copy-source-if-*`) are evaluated before the destination lock check, so those return `412` even when the destination is locked. | Wait for the retention period to expire. Refer to [bucket locks](/r2/buckets/bucket-locks/). | ### Upload and request errors diff --git a/src/content/docs/r2/buckets/bucket-locks.mdx b/src/content/docs/r2/buckets/bucket-locks.mdx index fee119d176b..78c95823237 100644 --- a/src/content/docs/r2/buckets/bucket-locks.mdx +++ b/src/content/docs/r2/buckets/bucket-locks.mdx @@ -150,6 +150,6 @@ If multiple rules apply to the same prefix or object key, the strictest (longest - Rules without prefix apply to all objects in the bucket. - Bucket locks protect both existing objects and objects created after the rule is enabled. They do not prevent new object creation. - Once a rule update succeeds, changes to protected objects are blocked from that point on. This includes overwrites, deletes, completing uploads that started earlier, and removal by lifecycle rules. -- A request blocked by a bucket lock rule fails with HTTP `409` and the `ObjectLockedByBucketPolicy` error code. The lock check runs before conditional headers such as `If-None-Match` or `If-Match` are evaluated, so a write that fails both checks returns `ObjectLockedByBucketPolicy`, not `PreconditionFailed` (`412`). In either case the existing object is not modified. +- A single-object S3 API request blocked by a bucket lock rule fails with HTTP `409` and the `ObjectLockedByBucketPolicy` error code. For multi-object deletes (`DeleteObjects`), R2 returns HTTP `200` and reports `ObjectLockedByBucketPolicy` for each locked key in the response body. The lock check runs before conditions on the object being written, such as `If-None-Match` or `If-Match`, so a write that fails both checks returns `ObjectLockedByBucketPolicy`, not `PreconditionFailed` (`412`). In either case the existing object is not modified. - Bucket lock rules take precedence over [lifecycle rules](/r2/buckets/object-lifecycles/). For example, if a lifecycle rule attempts to delete an object at 30 days but a bucket lock rule requires it be retained for 90 days, the object will not be deleted until the 90-day requirement is met. - A bucket cannot be emptied while any bucket lock rules are configured. Remove all lock rules before [emptying a bucket](/r2/buckets/delete-buckets/#empty-a-bucket). Bucket lock rules also apply when [deleting folders](/r2/objects/delete-objects/) from the dashboard. From 697725147c0a60f8563ecfc2272653aed67e5a39 Mon Sep 17 00:00:00 2001 From: helloimalastair Date: Tue, 27 Oct 2026 14:56:03 -0700 Subject: [PATCH 3/3] clarify 409 when same-object copy --- src/content/docs/r2/api/error-codes.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/docs/r2/api/error-codes.mdx b/src/content/docs/r2/api/error-codes.mdx index 5115966ae1a..d5546cf6b4e 100644 --- a/src/content/docs/r2/api/error-codes.mdx +++ b/src/content/docs/r2/api/error-codes.mdx @@ -63,7 +63,7 @@ For the **S3-compatible API**, errors are returned as XML in the response body: | 10020 | InvalidObjectName | 400 | Object key contains invalid characters or is too long. | Use valid UTF-8 characters. Maximum key length is 1024 bytes. | | 100100 | EntityTooLarge | 400 | Object exceeds maximum size (5 GiB for single upload, 5 TiB for multipart). | Use [multipart upload](/r2/objects/upload-objects/#multipart-upload) for objects larger than 5 GiB. Maximum object size is 5 TiB. | | 10012 | MetadataTooLarge | 400 | Custom metadata exceeds the 8,192 byte limit. | Reduce custom metadata size. Maximum is 8,192 bytes total for all custom metadata. | -| 10069 | ObjectLockedByBucketPolicy | 409 | Object is protected by a bucket lock rule and cannot be modified or deleted. If a conditional header on the object being written would also fail, this error is returned instead of `PreconditionFailed`. `CopyObject` source conditions (`x-amz-copy-source-if-*`) are evaluated before the destination lock check, so those return `412` even when the destination is locked. | Wait for the retention period to expire. Refer to [bucket locks](/r2/buckets/bucket-locks/). | +| 10069 | ObjectLockedByBucketPolicy | 409 | Object is protected by a bucket lock rule and cannot be modified or deleted. If a conditional header on the object being written would also fail, this error is returned instead of `PreconditionFailed`. When `CopyObject` copies to a different key, changes the storage class, or uses SSE-C, source conditions (`x-amz-copy-source-if-*`) are evaluated before the destination lock check and return `412`. When an object is copied onto itself, the lock check runs first and returns `409`. | Wait for the retention period to expire. Refer to [bucket locks](/r2/buckets/bucket-locks/). | ### Upload and request errors