astrid-runtime/astrid · error
legacy source changed before retirement: {}
Error message
legacy source changed before retirement: {} What it means
During retirement of a legacy source tree, retire_tree re-snapshots the path and compares it to the SourceIdentity recorded in the preflight ledger. If the tree still exists but its digest/entry-count/byte-count no longer match the snapshot — or a leaf's size/snapshot differs just before unlink — the library refuses to delete it and raises AlreadyExists. This is a data-safety abort: changed data must not be swept by migration.
Source
Thrown at crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs:248
}
}
Ok(())
}
pub(super) fn retire_tree(
path: &Path,
expected: &SourceIdentity,
protected: &[PathBuf],
) -> io::Result<()> {
let actual = snapshot_path(path)?;
if !actual.present {
// A prior post-ledger attempt completed its unlink before a crash.
// Absence is the idempotent terminal state regardless of whether the
// historical source identity was present.
return Ok(());
}
if &actual != expected {
return Err(io::Error::new(
io::ErrorKind::AlreadyExists,
format!(
"legacy source changed before retirement: {}",
path.display()
),
));
}
let metadata = fs::symlink_metadata(path)?;
if !metadata.is_dir() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"legacy retirement root is not a directory: {}",
path.display()
),
));
}
if active_mountpoint(path)? {View on GitHub (pinned to affd8760f4)
Solutions
- Stop all processes that write into the legacy directory, then re-run migration; the snapshot will be retaken and match.
- Identify what changed (compare against the ledger snapshot) and either revert the change or rerun preflight to record the new identity.
- Ensure only one migration process runs at a time; use a lock if embedding the library.
- Do not manually delete the tree to force retirement — use the supported migration path so provenance stays consistent.
Example fix
# before systemctl start legacy-astrid-daemon # keeps writing during migration // after systemctl stop legacy-astrid-daemon astrid migrate # rerun; retirement now sees an unchanged tree
Defensive patterns
Strategy: try-catch
Validate before calling
// Ensure no writer holds the legacy tree before migrating:
// fuser -v <legacy-path> (or lsof +D <legacy-path>) must return nothing.
fn quiesced(path: &std::path::Path) -> bool {
std::fs::read_dir(path).map(|mut d| d.next().is_none() || external_lsof_clean(path)).unwrap_or(false)
} Try / catch
match retire_post_barrier_sources(...) {
Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists
&& e.to_string().contains("changed before retirement") => {
eprintln!("legacy tree mutated during migration; stop writers and re-run");
// idempotent: safe to re-run the whole retirement
}
other => other?,
} Prevention
- Stop legacy daemons/services before starting migration
- Run only one migration instance at a time; use an exclusive lock
- Suspend backup/sync tools (Dropbox, rsync cron) for the legacy directory during migration
- Treat the error as retryable-after-quiescence, not as data loss — the tree is preserved
When it happens
Trigger: Any mutation of the legacy tree between preflight snapshot and retirement: files added, removed, or modified (digest or byte mismatch), a leaf file's size changing between retire_tree's leaf check and retire_leaf, or the path being replaced by different content. Raised recursively for every child via retire_tree and retire_leaf. Callers include retire_post_barrier_sources and the retirement tests.
Common situations: A running legacy daemon still writing logs/state into its old directory during migration; the user editing files in the legacy location mid-upgrade; a background sync/backup tool touching mtimes and content; concurrent second migration instance.
Related errors
- legacy component source reappeared during ordinary retiremen
- legacy capsule entry has a non-UTF-8 name
- workspace capsule manifest changed while it was being read:
- read capsule projection entry: {error}
- inspect capsule projection {}: {error}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/99dd966fd9c192ff.
Report an issue: GitHub.