astrid-runtime/astrid · error
legacy secrets root reappeared after cut-over
Error message
legacy secrets root reappeared after cut-over: {secrets_root} What it means
Thrown at the end of the legacy migration barrier audit when the legacy secrets root directory itself still exists but is empty. After full cut-over the entire legacy secrets root should be gone; an empty remnant is tolerated only when `allow_empty_cleanup` is set, otherwise the audit returns InvalidData rather than deleting user-visible directories behind the caller's back.
Solutions
- Delete the empty legacy secrets root directory (`rmdir <secrets_dir>`; rmdir fails safely if not empty).
- Re-run the audit with `allow_empty_cleanup` so the empty root is retired automatically.
- Remove any startup/config code that recreates the legacy secrets root directory.
- If the root is non-empty, complete the remaining secret imports first; a different error names what remains.
Defensive patterns
Strategy: validation
Validate before calling
let secrets_root = home.secrets_dir();
if secrets_root.exists()
&& std::fs::read_dir(&secrets_root)?.next().is_none()
{
std::fs::remove_dir(&secrets_root)?; // fails safely if not empty
}
verify_legacy_migration_barrier(&home, allow_empty_cleanup)?; Type guard
fn is_empty_dir(p: &std::path::Path) -> std::io::Result<bool> {
Ok(p.is_dir() && std::fs::read_dir(p)?.next().is_none())
} Try / catch
if let Err(e) = audit {
if e.kind() == std::io::ErrorKind::InvalidData {
eprintln!("legacy remnant: {e}; run with allow_empty_cleanup or rmdir the path");
}
} Prevention
- Do not `mkdir -p` the legacy secrets root in startup scripts.
- Enable allow_empty_cleanup so empty remnants are retired automatically.
- Audit backup-restore jobs for paths they recreate.
When it happens
Trigger: Running the migration verification when `home.secrets_dir()` exists with zero entries and `allow_empty_cleanup` is false. Also triggered when leftover principal/host subdirectories were cleaned but the root was left behind by an older tool version.
Common situations: Post-migration audit on a home where an older binary created the secrets root and never removed it; backup/restore tooling recreating the empty directory; scripts that `mkdir -p` the secrets path at startup.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- layout migration destination changed type
- layout migration destination changed while inventoried
- layout migration destination is redirected or not a regular…
- layout migration receipt destination path does not match…
- layout migration source is redirected or not a directory
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/7fa18d731bea4f93.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/legacy_migration_barrier/mod.rs:936
if allow_empty_cleanup {
retire_empty_directory(&host_secrets)?;
} else {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"legacy host secret source reappeared after cut-over: {}",
host_secrets.display()
),
));
}
}
if path_exists(&secrets_root)? {
let remaining = snapshot_path(&secrets_root)?;
if remaining.entries == 0 {
if allow_empty_cleanup {
retire_empty_directory(&secrets_root)?;
} else {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"legacy secrets root reappeared after cut-over: {}",
secrets_root.display()
),
));
}
}
}
Ok(())
}
#[cfg(test)]
mod tests;
View on GitHub (pinned to affd8760f4)