astrid-runtime/astrid · error
legacy env/secret source changed before import
Error message
legacy env/secret source changed before import: {name} What it means
Before importing, each legacy env/secret source is snapshotted (preflight). At import time the file is re-snapshotted and compared; if it differs from the preflight identity, the library aborts with `InvalidData` to prevent importing a file that changed mid-migration.
Solutions
- Stop processes that touch the legacy env files, then re-run the migration.
- Quiesce file-sync clients or pause them during migration.
- Restore the file to its pre-migration content or redo preflight so snapshots match.
Example fix
# before astrid migrate & # while syncd rewrites .env # after pause Dropbox; astrid migrate; resume Dropbox
Defensive patterns
Strategy: retry
Validate before calling
let before = snapshot_path(env_file)?;
std::thread::sleep(std::time::Duration::from_millis(200));
let after = snapshot_path(env_file)?;
if before != after { eprintln!("{env_file:?} is being modified; quiesce writers first"); } Try / catch
loop {
match migrate_legacy_layout(...) {
Err(e) if e.to_string().contains("changed before import") => {
attempts += 1;
if attempts > 3 { return Err(e.into()); }
std::thread::sleep(std::time::Duration::from_secs(1));
}
other => { other?; break; }
}
} Prevention
- Pause file-sync clients and editors during migration.
- Stop apps that rewrite .env files (dotenv watchers, secret rotators) before migrating.
- Run migration on local filesystems, not network mounts prone to metadata churn.
When it happens
Trigger: Calling `import_env_and_secrets` (via `require_scope_matches_ledger`) when the file's content/metadata changed between preflight snapshot and import; also exercised directly by tests `capsule_scope_import_rejects_source_that_changed_after_preflight` / `..._accepts_identical_...`.
Common situations: A running process (dotenv loader, editor autosave, sync client like Dropbox) rewrote the secret file during migration; user edited `.env` while migration ran; TOCTOU race on network mounts.
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
- capsule disappeared during durable contracts scan
- durable capsule disappeared after publish
- layout migration destination changed type
- layout migration destination changed while inventoried
- layout migration source changed type
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/e5c40333cc2405b1.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/legacy_migration_barrier/env_import.rs:104
return Err(io::Error::other(format!(
"legacy env/secret sources remain for {} (uid {}); migration API did not retire every scope",
status.alias, status.uid
)));
}
Ok(())
}
fn require_scope_matches_ledger(
snapshots: &BTreeMap<String, SourceIdentity>,
name: &str,
path: &Path,
) -> io::Result<()> {
let expected = snapshots
.get(name)
.ok_or_else(|| io::Error::other(format!("migration source inventory is missing {name}")))?;
let actual = snapshot_path(path)?;
if actual != *expected {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("legacy env/secret source changed before import: {name}"),
));
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::require_scope_matches_ledger;
use crate::legacy_migration_barrier::host_fs::snapshot_path;
use std::collections::BTreeMap;
use std::fs;
fn make_private_file(path: &std::path::Path) {
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt as _;View on GitHub (pinned to affd8760f4)