astrid-runtime/astrid · error
legacy audit source is not a regular directory: {}
Error message
legacy audit source is not a regular directory: {} What it means
retire_legacy_audit_dir refuses to rename the legacy audit source unless it is a plain, non-symlink directory. Using symlink_metadata (which does not follow symlinks), it rejects the path with InvalidData if the entry is a symlink or any non-directory file type, because retiring a redirected or non-directory path could destroy or bypass data outside the expected legacy layout.
Source
Thrown at crates/astrid-kernel/src/legacy_migration_barrier/host_fs.rs:465
let retired = home.migrations_dir().join("audit-principal-home.retired");
let expected = home.principal_home(&PrincipalId::default()).audit_dir();
if source != expected {
return Err(io::Error::new(
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(|| {
io::Error::new(
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 fs::symlink_metadata(source) {
Ok(metadata) if metadata.file_type().is_symlink() || !metadata.is_dir() => {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"legacy audit source is not a regular directory: {}",
source.display()
),
));
},
Ok(_) => {
if fs::symlink_metadata(&retired).is_ok() {
return Err(io::Error::new(
io::ErrorKind::AlreadyExists,
format!(
"legacy audit retirement is ambiguous: {}",
retired.display()
),
));
}
let root_device = device_id(&fs::symlink_metadata(source)?);View on GitHub (pinned to affd8760f4)
Solutions
- Remove the symlink/file at the legacy audit path and replace it with a real directory containing the legacy audit data, then re-run migration.
- If the symlink points at the real data, remove the link, move the data back into a plain directory at the expected path, and retry.
- Delete an empty or stale non-directory 'audit' entry so migration treats the source as absent and skips retirement.
Example fix
// before: audit is a symlink rm ~/ .astrid/principal/audit # symlink ln -s /mnt/big/audit ~/.astrid/principal/audit // after: real directory rm ~/.astrid/principal/audit mv /mnt/big/audit ~/.astrid/principal/audit
Defensive patterns
Strategy: validation
Validate before calling
match std::fs::symlink_metadata(&source) {
Ok(m) if m.file_type().is_symlink() || !m.is_dir() => {
return Err(format!("{} must be a real directory", source.display()));
},
Ok(_) | Err(e) if e.kind() == std::io::ErrorKind::NotFound => {},
Err(e) => return Err(e.into()),
} Type guard
fn is_plain_dir(p: &Path) -> bool {
std::fs::symlink_metadata(p).map(|m| m.is_dir() && !m.file_type().is_symlink()).unwrap_or(false)
} Try / catch
if let Err(e) = migrate_legacy_audit(&home, &source) {
if e.kind() == std::io::ErrorKind::InvalidData && e.to_string().contains("not a regular directory") {
// replace symlink/file with a real directory, then retry
}
} Prevention
- Avoid symlinking ~/.astrid paths via dotfile managers.
- Check symlink_metadata (not metadata) on legacy paths before migrating.
- Keep legacy audit data in a real directory on the home filesystem.
When it happens
Trigger: Calling migrate_legacy_audit when <principal home>/audit is a symlink (e.g. to another location), a regular file, fifo, socket, or other non-directory entry.
Common situations: Users symlinking the audit directory to a bigger disk or dotfiles-managed location; a stale file named 'audit' left where the directory used to be; dotfile managers (stow,chezmoi) replacing the directory with a symlink.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- legacy capsule directory is not a regular directory: {}
- legacy capsule entry is not a regular directory: {}
- capsule materialization target is redirected or not a direct
- legacy REPL history is not a regular file: {}
- layout migration destination is redirected or not a regular
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/ca6d358609206a20.
Report an issue: GitHub.