{"record":{"id":"b7aad9760e2f1a1b","repo":"astrid-runtime/astrid","slug":"legacy-log-conflict-at-detail","errorCode":null,"errorMessage":"legacy log conflict at {}: {detail}","messagePattern":"legacy log conflict at (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/principal_log_migration.rs","lineNumber":554,"sourceCode":"fn sync_parent(path: &Path) -> io::Result<()> {\n    #[cfg(unix)]\n    if let Some(parent) = path.parent() {\n        File::open(parent)?.sync_all()?;\n    }\n    #[cfg(not(unix))]\n    let _ = path;\n    Ok(())\n}\n\nfn invalid(path: &Path, detail: &str) -> io::Error {\n    io::Error::new(\n        io::ErrorKind::InvalidData,\n        format!(\"legacy log {}: {detail}\", path.display()),\n    )\n}\n\nfn conflict(path: &Path, detail: &str) -> io::Error {\n    io::Error::new(\n        io::ErrorKind::AlreadyExists,\n        format!(\"legacy log conflict at {}: {detail}\", path.display()),\n    )\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn migrates_logs_to_uid_projection_and_is_idempotent() {\n        let temp = tempfile::tempdir().unwrap();\n        let home = AstridHome::from_path(temp.path().join(\"astrid\"));\n        let principal = PrincipalId::new(\"alice\").unwrap();\n        let uid = PrincipalUid::from_bytes([0x91; 32]);\n        let directory = PrincipalDirectory::default();\n        directory.register(principal.clone(), uid).unwrap();\n        let source = home.principal_home(&principal).log_dir();","sourceCodeStart":536,"sourceCodeEnd":572,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/principal_log_migration.rs#L536-L572","documentation":"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.","triggerScenarios":"`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).","commonSituations":"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.","solutions":["Re-run the migration/idempotent admission pass — completed migrations are typically safe to resume and will reconcile leftovers","Remove or archive the conflicting destination path if you know it is a stale leftover","Ensure only one instance of the application performs migration at a time","Check the `detail` in the message to see exactly which expected-fresh path collided"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// preflight yourself: ensure expected-fresh destinations don't exist\nif destination_path.exists() {\n    archive_or_remove(&destination_path)?; // or abort and reconcile manually\n}","typeGuard":null,"tryCatchPattern":"match res {\n    Err(e) if e.kind() == io::ErrorKind::AlreadyExists => retry_migration_after_reconciling(),\n    other => other,\n}","preventionTips":["Run only one app instance during migration","Complete interrupted migrations before starting new ones","Don't restore backups on top of already-migrated homes without resetting"],"tags":["migration","conflict","filesystem"],"backgroundTag":"file-already-exists","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}