Managing Legal Holds on Spatial Datasets
A legal hold arrives with a scope described in words — “all survey and imagery relating to the northern corridor works between 2019 and 2022” — and has to become a set of object keys that cannot be deleted, with evidence that the scope was applied completely. This walkthrough is for the archive operator and compliance owner who must translate that sentence into storage-layer state, keep it in force for an unknown duration, and release it cleanly when the matter closes.
Holds Are Not Retention Periods
The two mechanisms look similar and behave differently in the ways that matter during litigation.
Step-by-Step Procedure
Step 1 — Turn the scope into a query, then into a manifest
The scope is described in domain terms; the archive is organised by prefix, tag and time. Bridging the two is the step that determines whether the hold is complete, and it belongs to the archivist rather than to the storage platform.
-- Scope: survey and imagery for the northern corridor works, 2019-2022
CREATE TABLE hold_2026_014_manifest AS
SELECT i.key, i.storage_class, c.collection, c.datetime
FROM spatial_archive_inventory i
JOIN stac_items c ON c.asset_key = i.key
WHERE c.collection IN ('aerial-imagery', 'lidar-classified', 'survey-control',
'utilities-asbuilt')
AND c.datetime BETWEEN TIMESTAMP '2019-01-01' AND TIMESTAMP '2022-12-31'
AND ST_Intersects(c.footprint,
ST_GeomFromText('POLYGON((...northern corridor...))', 27700));
Record the query itself alongside the manifest. When someone asks in two years how the scope was determined, the query is the answer — a list of keys is not.
Step 2 — Apply the hold as a batch operation
aws s3control create-job --account-id 123456789012 \
--operation '{"S3PutObjectLegalHold":{"LegalHold":{"Status":"ON"}}}' \
--manifest '{"Spec":{"Format":"S3BatchOperations_CSV_20180820","Fields":["Bucket","Key"]},
"Location":{"ObjectArn":"arn:aws:s3:::spatial-archive-logs/holds/2026-014.csv",
"ETag":"7c41…"}}' \
--report '{"Bucket":"arn:aws:s3:::spatial-archive-logs","Format":"Report_CSV_20180820",
"Enabled":true,"Prefix":"holds/2026-014","ReportScope":"AllTasks"}' \
--priority 30 --role-arn arn:aws:iam::123456789012:role/archive-batch --region us-east-1
Step 3 — Prove the hold is complete and in force
# Every object in the manifest reports a hold; count must equal the manifest length
while read -r bucket key; do
aws s3api get-object-legal-hold --bucket "$bucket" --key "$key" \
--query 'LegalHold.Status' --output text
done < holds/2026-014.csv | sort | uniq -c
# 18432 ON
Step 4 — Release deliberately, and record it
aws s3control create-job --account-id 123456789012 \
--operation '{"S3PutObjectLegalHold":{"LegalHold":{"Status":"OFF"}}}' \
--manifest file://holds/2026-014-release.json \
--report file://holds/2026-014-release-report.json \
--priority 30 --role-arn arn:aws:iam::123456789012:role/archive-batch --region us-east-1
Validation & Verification
python -m archive.holds audit --hold-id 2026-014
# manifest objects 18,432
# holds ON 18,432
# in scope but not held 0
# held but out of scope 0
# last re-scope 2026-08-01
# AUDIT PASS
Expected output is zero in both mismatch rows. “In scope but not held” is the serious one: it means data that should be preserved is deletable, and it appears whenever the scope query has not been re-run since new material arrived.
Troubleshooting
| Symptom | Root cause | Fix |
|---|---|---|
| Hold applies but objects still deletable | Bucket lacks Object Lock, enabled only at creation | The bucket cannot be retrofitted; migrate to a lock-enabled bucket |
| New data not covered | Scope applied once, never re-run | Schedule the scope query monthly for the life of the hold |
| Lifecycle expiry fails silently | Hold blocking deletion, as designed | Not an error; report it so nobody “fixes” the lifecycle rule |
| Release leaves some objects held | Release manifest generated from a stale scope | Release from the applied manifest, not from a fresh query |
| Cannot determine why an object is held | No hold identifier recorded on the object | Tag held objects with the hold id as well as setting the flag |
Operational Execution Checklist
What the Hold Costs While It Runs
A hold has no expiry, so its cost accrues indefinitely and is worth stating when it is applied. For spatial data the figure is usually modest and occasionally not, and the difference comes from what the hold blocks rather than from the storage it occupies.
State the annual figure when the hold is applied and revisit it at each review. A hold whose cost has grown because the scope keeps widening is one worth discussing with whoever requested it, and that conversation is easier with a number than with an impression.
Frequently Asked Questions
Can held objects still be moved between storage classes?
Yes. A legal hold blocks deletion and overwriting; it does not block transitions, and lifecycle rules continue to operate normally on held objects. That is usually desirable — a hold lasting years should not force the data to stay in an expensive class — but it means a held object may be in Deep Archive when it is called for, so plan the restore path as part of the response rather than as a surprise.
What happens to a hold if the matter ends and nobody removes it?
The objects stay protected indefinitely, which is a failure of a different kind: storage that cannot be released and an archive whose retention policy no longer describes its actual state. Holds should have an owner and a review date even though they have no expiry, and the review should ask whether the matter is still open rather than whether the hold is still needed.
How is a hold applied to data that has not been created yet?
It cannot be, directly — a hold is applied to objects. The practical arrangement is a standing scope query re-run on a schedule, combined with an ingest-time check that flags material matching an active hold’s scope so it is held on arrival rather than a month later. The gap between arrival and the next scope run is the exposure, and it is worth stating explicitly.
Who should be able to apply and release a hold?
Applying should be available to the archive operators, since delay creates risk; releasing should require the requesting authority’s confirmation, since a premature release destroys the protection the hold existed to provide. Separating the two permissions is a small piece of access-control design that prevents the most consequential mistake in this area.
How is a hold documented for someone who arrives later?
With the scope query, the manifest, the requesting reference, the date applied and the owner. Those five facts let a colleague two years later answer what is held, why, on whose authority, and whether the scope still matches the request — which is precisely the set of questions that arises when the original owner has moved on.
Can a hold cover data held by an upstream system rather than the archive?
Not through the archive’s controls, and the gap is worth naming explicitly. A hold applied to archived objects says nothing about the same material sitting in a working system, and preservation obligations usually cover both. Coordinating with the systems upstream is part of applying the hold, even though only the archive’s part is technically enforceable here.
What happens if the archive is migrated while a hold is in force?
The hold does not travel with the objects — it is storage-layer state, not file content — so a migration must reapply it in the destination before the source is released. That makes a migration under an active hold materially more complex than one without, and it is a reason to complete or at least stabilise holds before scheduling a platform move.
Can a hold be applied to a whole bucket rather than to objects?
Some platforms offer container-level immutability, which is coarser and simpler. It suits an archive whose holds are effectively permanent and organisation-wide; it suits a matter-scoped hold badly, because releasing it releases everything. Per-object holds with a recorded scope are the right instrument when the scope is narrower than the bucket.
Should holds be visible in the catalogue?
To operators, yes; to general users, usually not. Operators need to know why an object cannot be deleted; users mostly do not, and exposing an active matter’s scope through a public catalogue is rarely appropriate. A held flag visible to authenticated operators strikes the right balance.
Related
- Retention Policy Frameworks — the parent topic covering retention modes and the erasure conflict.
- Configuring S3 Object Lock for Compliance Spatial Archives — provisioning the lock that makes holds possible.
- Implementing Lifecycle Rules for Shapefile Archives — why multi-file datasets need tag-scoped rules, which also makes them scopeable for holds.
- Indexing Archived Imagery Footprints for Fast Discovery — the spatial index that makes a geographic hold scope resolvable at all.
Up one level: Retention Policy Frameworks.