astrid-runtime/astrid · error

legacy audit retirement source is outside the default princi

Error message

legacy audit retirement source is outside the default principal audit path

What it means

The legacy audit retirement routine only accepts a source path equal to the default principal's audit_dir; any other path is refused with InvalidInput. This guard prevents callers from renaming arbitrary directories into the migrations area under the guise of a legacy audit migration.

Source

Thrown at crates/astrid-kernel/src/lib.rs:4251

        tracing::info!(
            total_sessions = results.len(),
            "Audit chain verification passed for all sessions"
        );
    }
    Ok(())
}

#[cfg(unix)]
pub(crate) fn retire_legacy_audit_dir(
    home: &astrid_core::dirs::AstridHome,
    source: &Path,
) -> std::io::Result<()> {
    let retired = home.migrations_dir().join("audit-principal-home.retired");
    let expected = home
        .principal_home(&astrid_core::PrincipalId::default())
        .audit_dir();
    if source != expected {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidInput,
            "legacy audit retirement source is outside the default principal audit path",
        ));
    }
    astrid_core::platform_fs::verify_no_redirects(source.parent().ok_or_else(|| {
        std::io::Error::new(
            std::io::ErrorKind::InvalidInput,
            "legacy audit source has no parent",
        )
    })?)?;
    astrid_core::platform_fs::ensure_private_directory(&home.migrations_dir())?;
    astrid_core::platform_fs::verify_no_redirects(&home.migrations_dir())?;
    match std::fs::symlink_metadata(source) {
        Ok(metadata) if metadata.file_type().is_symlink() || !metadata.is_dir() => {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidData,
                format!(
                    "legacy audit source is not a regular directory: {}",

View on GitHub (pinned to affd8760f4)

Solutions

  1. Construct the source path via home.principal_home(PrincipalId::default()).audit_dir() instead of hard-coding it
  2. Use canonicalized paths on both sides so path formatting differences do not cause a mismatch
  3. If you truly need to retire a non-default audit tree, do it manually rather than through this API

Example fix

// before
retire_legacy_audit(&home, &Path::new("~/.app/audit"))?;
// after
let source = home.principal_home(astrid_core::PrincipalId::default()).audit_dir();
retire_legacy_audit(&home, &source)?;
Defensive patterns

Strategy: validation

Validate before calling

let expected = home.principal_home(astrid_core::PrincipalId::default()).audit_dir();
assert_eq!(source, expected, "source must be the default principal audit_dir");

Type guard

fn is_expected_source(source: &std::path::Path, home: &Home) -> bool {
    source == home.principal_home(astrid_core::PrincipalId::default()).audit_dir()
}

Try / catch

if let Err(e) = retire_legacy_audit(&home, &source) {
    if e.kind() == std::io::ErrorKind::InvalidInput
        && e.to_string().contains("outside the default principal audit path") {
        // rebuild source via the home API and retry
    } else { return Err(e.into()); }
}

Prevention

When it happens

Trigger: Calling retire_legacy_audit (or the migration that uses it) with a source path that differs from home.principal_home(PrincipalId::default()).audit_dir().

Common situations: Passing a custom or relative audit path; migrating a non-default principal; hard-coding the audit path instead of building it via the home API so it no longer matches byte-for-byte.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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