Why does expiring old snapshots in a lakehouse table break time travel to last month?
answer
- the history is gone, and so are its files
- the cleanup job did what you told it to
- retention is your recovery window
- no surviving version, nothing to resolve
- expiry deletes data, not just metadata
basics
~20 sSnapshot expiry drops old versions from the table's history and deletes the data files no surviving snapshot still references. Once that runs, any AS OF query or rollback to a point before the retention horizon has neither a snapshot to resolve nor files to read.
solid answer
~60 sTime travel works because old snapshots still exist and the files they reference were never deleted. **Expiry is the operation that ends both conditions.** It removes snapshots older than the configured retention and then garbage-collects every data file that no remaining snapshot references — which is the whole point, since otherwise every rewritten or compacted file would be kept forever. Afterwards, a query `AS OF` an expired point fails to resolve a version, and a rollback to it is impossible; the retention window *is* your recovery window. Two related failures look similar and are worth separating. First, a long-running query pinned to a snapshot that expiry removes mid-flight can fail with missing files. Second, **orphan-file cleanup** deletes unreferenced objects, and if its age threshold is shorter than your longest in-flight write, it can delete files a live writer staged — a genuine corruption risk, not just a broken query. The fix in all three cases is policy: set retention to cover your detection-and-recovery window, keep the orphan threshold well above the longest write, and protect any snapshot you must be able to reproduce.
code
text · 11 linesbefore expiry (retention = 30 days)
oldest surviving version: 118 (2026-07-05)
current version: 412 (2026-08-21)
SELECT ... TIMESTAMP AS OF '2026-07-20' -> OK (resolves v240)
nightly maintenance: expire snapshots older than 7 days
removes v118..v380 and deletes files only they referenced
after expiry
oldest surviving version: 381 (2026-08-14)
SELECT ... TIMESTAMP AS OF '2026-07-20' -> FAILS: no version at or before that timego deeper
Know that old versions do not last forever: a retention setting decides how far back time travel reaches, and a cleanup job removes everything older.
Explain that expiry deletes the data files no surviving snapshot references, not just history entries, and that this is why storage is reclaimed at all.
Diagnose it as a policy event rather than a bug: check requested version, oldest surviving version, retention config and maintenance schedule. Know the long-reader and orphan-threshold failures too.
Own retention as a recovery objective: how long until a bad write is detected, what must remain reproducible, and how the same setting doubles as the floor on compliance-deletion latency.
## Why expiry has to exist History in a table format is free to *create* and expensive to *keep*. Every update, delete and compaction writes replacement files while the old ones stay alive for as long as some snapshot references them. A table compacted nightly can hold several multiples of its live data in files that only history needs. Expiry is the release valve: drop snapshots older than a retention period, then delete every data file that no surviving snapshot references. That second half is what surprises people. Expiry is not a metadata tidy-up; it **deletes data files**. Once the file is gone, the snapshot that referenced it could not be read even if you somehow kept its metadata. ## What actually breaks After expiry with, say, a seven-day retention: - `TIMESTAMP AS OF` or `VERSION AS OF` a point older than seven days fails — there is no such version to resolve. - Rollback to a pre-horizon version is impossible. **The retention window is the recovery window**, so a bad write discovered on day nine is unrecoverable by rollback. - Reproducing a report or a training set pinned to an old version fails, which is why version ids recorded in an experiment tracker are only as durable as the retention policy behind them. The interview payoff line is the causal one: time travel did not "stop working", a maintenance job did exactly what it was configured to do. ## Diagnosing it When someone reports that time travel broke, work in this order: what version or timestamp were they asking for; what does the table's history show as the oldest surviving version; what is the retention setting; and did a maintenance job run between the last successful attempt and the failure. Almost always the oldest surviving version now sits after the requested point, and the change was a schedule or a config, not the table. ## The two adjacent failures **A long reader losing its files.** A query that resolved a snapshot at planning time reads that snapshot's file list for its whole run. If expiry removes that snapshot and deletes files while the scan is still going, the scan dies with a missing-file error partway through — the reader's isolation guarantee is only as good as the files' continued existence. Keep retention comfortably longer than your longest query, and prefer running expiry when heavy readers are not active. **Orphan cleanup deleting live work.** Orphan-file removal deletes objects under the table location that no snapshot references *and* that are older than an age threshold. In-flight writes look exactly like orphans, because they are unreferenced by design until commit. If the threshold is shorter than the longest write, cleanup can delete a writer's staged files, and the resulting commit references objects that no longer exist. This is the one failure here that produces genuine corruption rather than a failed query, and the mitigation is simple: threshold well above the longest possible write, and never run it with an aggressive value "to save space quickly". ## Policy fixes - **Set retention from the detection window, not from a round number.** How long until a bad write is noticed — a failed data-quality check, a Monday-morning dashboard, a monthly close? Retention must exceed that, plus slack. - **Protect what you must reproduce.** Where the format supports pinning or naming specific snapshots so expiry skips them, use it for audit or model-training points. Where it does not, snapshot the state into a separate table — copy the data, do not rely on history. - **Separate the knobs.** Retention (how far back you can travel), the orphan age threshold (safety margin for in-flight writes), and how often maintenance runs are three independent decisions that are often wrongly set together. - **Watch the cost side too.** Long retention plus frequent compaction is the combination that quietly triples storage, because each rewrite's superseded files stay pinned by every snapshot in the window. ## What expiry does not do It does not compact, it does not fix small files, and it does not remove files a surviving snapshot still needs. It also does not make deleted rows unrecoverable immediately: rows removed for a compliance request remain readable through any unexpired snapshot that still references their file, so your retention period is effectively a floor on how long that data survives.
- A long-running scan fails partway with a missing-file error. What is the most likely cause?A maintenance job expired snapshots and deleted files the query's pinned snapshot still referenced. The reader resolved its file list at planning time and has been reading it ever since, so its isolation lasts only as long as the files do. Keep retention longer than your longest query and schedule expiry away from heavy readers.
- How do you choose the age threshold for orphan-file cleanup?It must exceed the longest possible in-flight write, with margin. In-flight writes are unreferenced by definition, so they are indistinguishable from orphans; a threshold shorter than your slowest job lets cleanup delete files a writer is about to commit, producing a commit that references missing objects. That is corruption, not a retry.
- A row was deleted for a compliance request. When is the data really gone?Not at the delete — the old file still contains it and every unexpired snapshot referencing that file can still read it. It is gone only once those snapshots expire and the file is garbage-collected. Retention therefore sets a floor on your deletion SLA, and meeting a tighter one means shortening retention or forcing expiry for that table.
- How would you keep one specific version reproducible for an audit without extending retention for everything?Protect that single snapshot where the format allows pinning or naming versions so expiry skips it, which keeps only its files alive. Where that is unavailable, materialise the state into a separate table with its own lifecycle. Extending table-wide retention to preserve one point is the expensive answer and pins every intermediate version's files too.
saying these in an interview costs you the question
- Thinks expiry only trims metadata and leaves data files
- Assumes rollback works regardless of the retention window
- Sets the orphan cleanup threshold shorter than the longest write
- Says a running query is immune because it already resolved a snapshot
- Believes deleted rows are unreadable immediately after the delete commit