astrid-runtime/astrid · error
legacy secret source reappeared after completed migration: {
Error message
legacy secret source reappeared after completed migration: {path} What it means
Raised by `ensure_legacy_secret_deletion_allowed`: the legacy secret directory for a principal still exists (`secrets_dir/<principal>`), and the migration ledger records that this principal's secret source was migrated away (`source.present == false`). After a completed migration the legacy source must not exist, so its reappearance is blocked with WouldBlock to prevent operating on stale, untracked secrets.
Source
Thrown at crates/astrid-kernel/src/legacy_migration_barrier/secret.rs:49
let ledger: MigrationLedger = decode_canonical(&bytes, &path)?;
let name = format!("principal:{uid}:secrets");
let component = ledger
.components
.iter()
.find(|component| component.name == name);
Ok(component.is_some_and(|component| !component.source.present))
}
pub(crate) fn ensure_legacy_secret_deletion_allowed(
home: &AstridHome,
principal: &PrincipalId,
uid: PrincipalUid,
) -> io::Result<()> {
let path = home.secrets_dir().join(principal.as_str());
match fs::symlink_metadata(&path) {
Ok(_) => {
if legacy_secret_source_must_be_absent(home, uid)? {
return Err(io::Error::new(
io::ErrorKind::WouldBlock,
format!(
"legacy secret source reappeared after completed migration: {}",
path.display()
),
));
}
},
Err(error) if error.kind() == io::ErrorKind::NotFound => (),
Err(error) => return Err(error),
}
Ok(())
}
#[cfg(test)]
pub(crate) fn record_absent_legacy_secret_for_test(
home: &AstridHome,
uid: PrincipalUid,View on GitHub (pinned to affd8760f4)
Solutions
- Inspect and remove the reappeared legacy directory `<secrets_dir>/<principal>` after confirming no needed data lives there (its contents were migrated).
- Reconcile the ledger: if the migration actually did not complete, update/redo the import so `source.present` reflects reality.
- Check for old-version processes or backup jobs that recreate the legacy path and stop them.
- Re-run the deletion/verification flow after cleanup.
Defensive patterns
Strategy: try-catch
Validate before calling
let legacy = home.secrets_dir().join(principal.as_str());
if legacy.symlink_metadata().is_ok() {
eprintln!("legacy secret dir still exists for {principal}; reconcile ledger before deletion");
} Type guard
fn legacy_secret_path_exists(home: &AstridHome, principal: &PrincipalId) -> bool {
home.secrets_dir().join(principal.as_str()).symlink_metadata().is_ok()
} Try / catch
match ensure_legacy_secret_deletion_allowed(&home, &principal, uid) {
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {
eprintln!("legacy secret source reappeared; inspect {} before retry", e);
}
other => other?,
} Prevention
- After migration, delete (not archive in place) the legacy per-principal secret directory.
- Prevent old-version binaries from running against the migrated home.
- Reconcile the ledger whenever legacy paths are found post-migration.
When it happens
Trigger: Calling `ensure_legacy_secret_deletion_allowed` when `fs::symlink_metadata(secrets_dir/<principal>)` succeeds AND `legacy_secret_source_must_be_absent` returns true — i.e. the ledger says migration completed for `principal:<uid>:secrets` but the legacy directory is back on disk.
Common situations: Restoring the legacy secrets directory from a backup after migration; an old kernel version recreating per-principal secret dirs; a copy operation that resurrected the legacy path during maintenance.
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
- legacy env/secret status exceeds the bounded principal limit
- --capsule is required; native default env storage was retire
- principal migration ledger is missing the ordinary-home comp
- principal migration component has no ordinary-home receipt:
- destination receipt changed for migration component {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/b524b1c9b9437da4.
Report an issue: GitHub.