diff --git a/src/content/docs/r2/api/error-codes.mdx b/src/content/docs/r2/api/error-codes.mdx index ec69ca19bae..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 | 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 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 diff --git a/src/content/docs/r2/buckets/bucket-locks.mdx b/src/content/docs/r2/buckets/bucket-locks.mdx index 9d9009e01e3..78c95823237 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 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.