astrid-runtime/astrid · error
legacy secret source reappeared after cut-over
Error message
legacy secret source reappeared after cut-over: {} What it means
When cut-over is complete, legacy secret source directories must stay empty. If a directory has content again and empty-dir cleanup is not allowed (`allow_empty_cleanup == false`), the library raises `InvalidData` because a legacy secret source reappeared after migration, meaning aliases would shadow live data.
Solutions
- Find and stop whatever is writing to the legacy path (process, cron, sync client), remove the recreated files, and re-run migration.
- Update applications to use the new secret location instead of the legacy root.
- Run migration with cleanup allowed only after confirming nothing recreates legacy content.
Example fix
# before: cron writes to old path 0 * * * * write-secret legacy-secrets/api/token.txt # after 0 * * * * write-secret .astrid/secrets/api/token.txt
Defensive patterns
Strategy: try-catch
Validate before calling
fn legacy_quiet(legacy_root: &std::path::Path) -> bool {
std::fs::read_dir(legacy_root).map(|rd| rd.filter_map(Result::ok)
.all(|e| std::fs::read_dir(e.path()).map(|mut d| d.next().is_none()).unwrap_or(true)))
.unwrap_or(true)
} Try / catch
match ensure_legacy_secret_aliases(root, ...) {
Err(e) if e.to_string().contains("reappeared after cut-over") => {
eprintln!("something rewrote legacy secrets; stop writers, clean, re-run");
return Err(e.into());
}
other => other,
} Prevention
- Identify and stop cron jobs/apps still writing to legacy secret paths.
- Update all writers to the new secret location before cut-over.
- Monitor legacy root for recreation after migration (e.g. inotify watcher).
When it happens
Trigger: Calling `ensure_legacy_secret_aliases` after cut-over when a previously retired legacy directory contains files again and the `allow_empty_cleanup` path was not taken (i.e. the error branch runs instead of `retire_empty_directory`).
Common situations: An application or cron job rewrote secrets into the old legacy location after migration; a restore/sync tool recreated old files; the migration was run twice with an app still writing legacy paths.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- layout migration destination changed type
- layout migration destination changed while inventoried
- layout migration source changed type
- capsule source disappeared while preparing replacement
- InvalidData
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/8c95efd70b1920c6.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs:121
for entry in entries {
if entry.file_name() == "__host__" {
continue;
}
let path = entry.path();
let snapshot = snapshot_path(&path)?;
if snapshot.entries != 0 {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"legacy secret source remains after migration: {}",
path.display()
),
));
}
if allow_empty_cleanup {
retire_empty_directory(&path)?;
} else {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"legacy secret source reappeared after cut-over: {}",
path.display()
),
));
}
}
Ok(())
}
/// Collect capsule directories below a workspace portal without following
/// redirects. The migration barrier uses this inventory when checking that
/// no legacy authority receipts remain attached to a workspace capsule.
pub(super) fn collect_workspace_targets(root: &Path) -> io::Result<Vec<PathBuf>> {
const MAX_WORKSPACE_TARGETS: usize = 4096;
let metadata = match fs::symlink_metadata(root) {
Ok(metadata) => metadata,View on GitHub (pinned to affd8760f4)