astrid-runtime/astrid · error

legacy log conflict at {}: {detail}

Error message

legacy log conflict at {}: {detail}

What it means

The `conflict(path, detail)` helper raises an AlreadyExists error when something the migration wants to create or move to already exists in an unexpected way at the destination path. Unlike plain `invalid`, this is a collision problem, not malformed content. The message names the conflicting path and a specific detail.

Source

Thrown at crates/astrid-kernel/src/principal_log_migration.rs:554

fn sync_parent(path: &Path) -> io::Result<()> {
    #[cfg(unix)]
    if let Some(parent) = path.parent() {
        File::open(parent)?.sync_all()?;
    }
    #[cfg(not(unix))]
    let _ = path;
    Ok(())
}

fn invalid(path: &Path, detail: &str) -> io::Error {
    io::Error::new(
        io::ErrorKind::InvalidData,
        format!("legacy log {}: {detail}", path.display()),
    )
}

fn conflict(path: &Path, detail: &str) -> io::Error {
    io::Error::new(
        io::ErrorKind::AlreadyExists,
        format!("legacy log conflict at {}: {detail}", path.display()),
    )
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn migrates_logs_to_uid_projection_and_is_idempotent() {
        let temp = tempfile::tempdir().unwrap();
        let home = AstridHome::from_path(temp.path().join("astrid"));
        let principal = PrincipalId::new("alice").unwrap();
        let uid = PrincipalUid::from_bytes([0x91; 32]);
        let directory = PrincipalDirectory::default();
        directory.register(principal.clone(), uid).unwrap();
        let source = home.principal_home(&principal).log_dir();

View on GitHub (pinned to affd8760f4)

Solutions

  1. Re-run the migration/idempotent admission pass — completed migrations are typically safe to resume and will reconcile leftovers
  2. Remove or archive the conflicting destination path if you know it is a stale leftover
  3. Ensure only one instance of the application performs migration at a time
  4. Check the `detail` in the message to see exactly which expected-fresh path collided
Defensive patterns

Strategy: retry

Validate before calling

// preflight yourself: ensure expected-fresh destinations don't exist
if destination_path.exists() {
    archive_or_remove(&destination_path)?; // or abort and reconcile manually
}

Try / catch

match res {
    Err(e) if e.kind() == io::ErrorKind::AlreadyExists => retry_migration_after_reconciling(),
    other => other,
}

Prevention

When it happens

Trigger: `migrate_one`, `preflight_destination`, `copy_entry`, `verify_entries`, `retire_source`, or `remove_empty_directories` find an existing file/directory where the migration expects none (destination entry already present, source reappeared after retirement, unexpected leftovers).

Common situations: A previous partially-completed migration left destination files behind; the user restored a backup on top of an already-migrated home; two instances of the app ran migrations concurrently.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/b7aad9760e2f1a1b. Report an issue: GitHub.