Which approach should I use to bulk-restore R2 object versions while excluding intentionally deleted objects?
0 reputation · 08 Oct 2020, 03:07 UTC
0 reputation · 08 Oct 2020, 03:07 UTC
I have an R2 bucket with object versioning enabled, and I need to recover a large number of objects after an accidental mass overwrite and deletion event. From the documentation, restoring a prior version means copying that version forward or removing delete markers via the S3-compatible API — there is no single "restore bucket to a timestamp" operation, so this has to be scripted.
The part I cannot resolve is how to distinguish objects that were intentionally deleted weeks ago from objects deleted during the incident. Listing versions and blindly removing every delete marker would resurrect data that was supposed to stay gone. I have object metadata (ETag, size, last-modified per version) available, but no application-level audit log of deletions.
I also understand that ETags from multipart uploads are not plain MD5 hashes of the content, so checksum verification against a pre-incident manifest needs to account for that.
My questions:
Assume current R2 behavior as of late 2026; I will verify against the latest docs before running anything in production.
32775 reputation · 08 Oct 2020, 12:16 UTC
To recover only the data lost in the accidental overwrite, keep versioning enabled and use ListObjectVersions with a time‑window filter. This returns every version and delete marker with a LastModified timestamp, so you can exclude delete markers that were created before the incident.
StartAfter and EndAfter (or the equivalent query parameters) when calling ListObjectVersions.
client.list_object_versions(
Bucket='my-bucket',
StartAfter='2026-10-01T00:00:00Z',
EndAfter='2026-10-02T23:59:59Z'
)
From the returned list, keep only delete markers whose LastModified falls inside the incident window. Delete markers created earlier remain untouched, preserving intentional deletions.
PUT /{bucket}/{key}?versionId={oldVersionId} (this creates a new current version).Multipart uploads produce ETags in the form <md5>-<partCount>. Compare the full string directly to your pre‑incident manifest. If you only have the part MD5s, recombine them as the service does: compute the MD5 of the concatenated part MD5s and append ".partCount".
Suspending versioning would convert delete markers into hard deletes, erasing the intentional deletions you want to keep. Keep versioning enabled throughout the script; the restore operations will simply create new versions.
s3:ListObjectVersionss3:GetObjects3:PutObjectDo you have a separate record of keys that were intentionally deleted before the incident? If so, we can cross‑reference that list to skip them even if their delete markers fall within the incident window.
By filtering delete markers by LastModified, preserving versioning, and verifying ETags for multipart uploads, you can bulk‑restore only the unintended data loss while keeping intentional deletions intact.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.