astrid-runtime/astrid · error

unsupported legacy audit source {}; only the default princip

Error message

unsupported legacy audit source {}; only the default principal source is admitted

What it means

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.

Source

Thrown at crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs:430

            Err(error) => return Err(error),
        }
        let audit_source = local_root.join("audit");
        let audit_metadata = match fs::symlink_metadata(&audit_source) {
            Ok(metadata) => metadata,
            Err(error) if error.kind() == io::ErrorKind::NotFound => continue,
            Err(error) => return Err(error),
        };
        if audit_source == default_source {
            default_source_present = true;
            validate_audit_tree(&audit_source, device_id(&audit_metadata))?;
        } else if fs::read_dir(&audit_source)
            .map_err(io::Error::other)?
            .next()
            .transpose()
            .map_err(io::Error::other)?
            .is_some()
        {
            return Err(io::Error::new(
                io::ErrorKind::AlreadyExists,
                format!(
                    "unsupported legacy audit source {}; only the default principal source is admitted",
                    audit_source.display()
                ),
            ));
        }
    }
    Ok(default_source_present)
}

/// Retire the imported default audit tree through a private staging rename.
/// The rename makes interrupted deletion resumable, while every pre/post
/// traversal revalidates no-follow, regular-entry, device, and mount bounds.
#[cfg(not(unix))]
pub(super) fn retire_legacy_audit_dir(home: &AstridHome, source: &Path) -> io::Result<()> {
    let retired = home.migrations_dir().join("audit-principal-home.retired");
    let expected = home.principal_home(&PrincipalId::default()).audit_dir();

View on GitHub (pinned to affd8760f4)

Solutions

  1. Archive or manually export the non-default principal's audit data, then empty or remove that audit directory and re-run.
  2. Confirm the extra audit tree is obsolete and delete it (it will not be migrated by design).
  3. If the data must be kept in-system, migrate it under the default principal id first, then run the legacy migration.
  4. Re-run migrate_legacy_audit once only the default principal's non-empty audit source remains.

Example fix

// before: second principal with audit data
/home/u/principal-abc/.local/audit/  (3 files)
// after
$ tar czf principal-abc-audit.tgz -C /home/u/principal-abc/.local audit
$ rm -r /home/u/principal-abc/.local/audit
Defensive patterns

Strategy: validation

Validate before calling

fn non_default_audit_sources(home_root: &std::path::Path, default_audit: &std::path::Path) -> std::io::Result<Vec<std::path::PathBuf>> {
    let mut offenders = Vec::new();
    for e in std::fs::read_dir(home_root)? {
        let audit = e?.path().join(".local").join("audit");
        if audit != default_audit
            && std::fs::symlink_metadata(&audit).map(|m| m.is_dir()).unwrap_or(false)
            && std::fs::read_dir(&audit)?.next().is_some()
        {
            offenders.push(audit);
        }
    }
    Ok(offenders) // archive/delete these before migrating
}

Try / catch

match result {
    Err(e) if e.kind() == std::io::ErrorKind::AlreadyExists && e.to_string().contains("unsupported legacy audit source") => {
        // archive/remove the named non-default audit tree, then retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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