{"record":{"id":"7379c3756e44172b","repo":"astrid-runtime/astrid","slug":"unsupported-legacy-audit-source-only-the-defau","errorCode":null,"errorMessage":"unsupported legacy audit source {}; only the default principal source is admitted","messagePattern":"unsupported legacy audit source (.+?); only the default principal source is admitted","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs","lineNumber":430,"sourceCode":"            Err(error) => return Err(error),\n        }\n        let audit_source = local_root.join(\"audit\");\n        let audit_metadata = match fs::symlink_metadata(&audit_source) {\n            Ok(metadata) => metadata,\n            Err(error) if error.kind() == io::ErrorKind::NotFound => continue,\n            Err(error) => return Err(error),\n        };\n        if audit_source == default_source {\n            default_source_present = true;\n            validate_audit_tree(&audit_source, device_id(&audit_metadata))?;\n        } else if fs::read_dir(&audit_source)\n            .map_err(io::Error::other)?\n            .next()\n            .transpose()\n            .map_err(io::Error::other)?\n            .is_some()\n        {\n            return Err(io::Error::new(\n                io::ErrorKind::AlreadyExists,\n                format!(\n                    \"unsupported legacy audit source {}; only the default principal source is admitted\",\n                    audit_source.display()\n                ),\n            ));\n        }\n    }\n    Ok(default_source_present)\n}\n\n/// Retire the imported default audit tree through a private staging rename.\n/// The rename makes interrupted deletion resumable, while every pre/post\n/// traversal revalidates no-follow, regular-entry, device, and mount bounds.\n#[cfg(not(unix))]\npub(super) fn retire_legacy_audit_dir(home: &AstridHome, source: &Path) -> io::Result<()> {\n    let retired = home.migrations_dir().join(\"audit-principal-home.retired\");\n    let expected = home.principal_home(&PrincipalId::default()).audit_dir();","sourceCodeStart":412,"sourceCodeEnd":448,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs#L412-L448","documentation":"The legacy importer only admits the default principal's audit source. If preflight finds a non-default <principal>/.local/audit directory that is non-empty, it aborts with AlreadyExists, refusing to migrate or delete audit data belonging to a non-default principal. Empty non-default audit directories are tolerated and skipped.","triggerScenarios":"migrate_legacy_audit when a second (non-default) principal directory under the home root contains .local/audit with at least one entry (fs::read_dir(...).next().is_some(), host_fs.rs:423-429).","commonSituations":"Machines where astrid was previously run by or for more than one principal, leaving old audit trees; copied home directories containing several principals' data; test fixtures with multiple principal dirs.","solutions":["Archive or manually export the non-default principal's audit data, then empty or remove that audit directory and re-run.","Confirm the extra audit tree is obsolete and delete it (it will not be migrated by design).","If the data must be kept in-system, migrate it under the default principal id first, then run the legacy migration.","Re-run migrate_legacy_audit once only the default principal's non-empty audit source remains."],"exampleFix":"// before: second principal with audit data\n/home/u/principal-abc/.local/audit/  (3 files)\n// after\n$ tar czf principal-abc-audit.tgz -C /home/u/principal-abc/.local audit\n$ rm -r /home/u/principal-abc/.local/audit","handlingStrategy":"validation","validationCode":"fn non_default_audit_sources(home_root: &std::path::Path, default_audit: &std::path::Path) -> std::io::Result<Vec<std::path::PathBuf>> {\n    let mut offenders = Vec::new();\n    for e in std::fs::read_dir(home_root)? {\n        let audit = e?.path().join(\".local\").join(\"audit\");\n        if audit != default_audit\n            && std::fs::symlink_metadata(&audit).map(|m| m.is_dir()).unwrap_or(false)\n            && std::fs::read_dir(&audit)?.next().is_some()\n        {\n            offenders.push(audit);\n        }\n    }\n    Ok(offenders) // archive/delete these before migrating\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists && e.to_string().contains(\"unsupported legacy audit source\") => {\n        // archive/remove the named non-default audit tree, then retry\n    }\n    other => other?,\n}","preventionTips":["Inventory all principal directories under the home root before migrating.","Archive and remove audit data belonging to non-default principals first.","Remember only the default principal's audit source is migrated — empty extras are fine."],"tags":["migration","multi-principal","unsupported","audit"],"backgroundTag":"unsupported-operation","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"}