astrid-runtime/astrid · error
legacy principal-home root is not a directory
Error message
legacy principal-home root is not a directory: {root} What it means
A legacy-layout preflight checks that the principal-home root (`home.home_dir()`) is a plain directory. If `symlink_metadata` shows it is a symlink or not a directory, the check fails with InvalidData: legacy homes must be real directories so that redirects/symlinks cannot smuggle secrets or layout state outside the audited tree.
Solutions
- Replace the symlink with a real directory (move the target's contents into the path and delete the link).
- Run the tool with HOME / AstridHome pointing at a real directory, not a symlinked one.
- If a file occupies the path, move it aside and create the directory.
- Re-run the legacy audit after the path is a plain directory.
Example fix
// before: home path is a symlink ~/.astrid -> /mnt/data/astrid // after mv ~/.astrid ~/astrid-real && rm ~/.astrid mv ~/astrid-real ~/.astrid # real directory, no symlink
Defensive patterns
Strategy: validation
Validate before calling
let root = home.home_dir();
let md = std::fs::symlink_metadata(&root)?;
if md.file_type().is_symlink() || !md.is_dir() {
return Err(format!("{} must be a real directory, not a symlink/file", root.display()));
} Type guard
fn is_plain_dir(p: &std::path::Path) -> bool {
match std::fs::symlink_metadata(p) {
Ok(md) => !md.file_type().is_symlink() && md.is_dir(),
Err(_) => false,
}
} Try / catch
match run_legacy_home_audit(&home) {
Err(e) if e.kind() == std::io::ErrorKind::InvalidData && e.to_string().contains("not a directory") => {
eprintln!("replace the symlink with a real directory, then retry");
}
other => other?,
} Prevention
- Do not let dotfile managers symlink the Astrid home directory itself.
- Run the audit only when home paths are plain directories.
- Check with `ls -la` (or symlink_metadata) before pointing the kernel at a home path.
When it happens
Trigger: Running the legacy principal-home audit when the home path is a symlink (e.g. `$HOME` resolved through a symlinked dotdir) or a file/mount point rather than a directory.
Common situations: Dotfile managers replacing config directories with symlinks (chezmoi, stow, dotbot); home on a symlinked path; a stray file occupying the home path after a bad restore.
Related errors
- legacy audit tree is redirected or not a directory
- legacy principal-home entry is not a regular directory
- legacy principal home root is not a regular directory
- legacy principal profile is not a regular file
- Astrid durable media is redirected or not a regular file
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/891717d904188766.
Report an issue: GitHub.
Appendix: source
Thrown at crates/astrid-kernel/src/lib.rs:4123
})?;
Ok(Arc::new(audit_log))
}
/// Enforce the released audit-source contract before opening any native
/// database. The first released layout had one system audit directory under
/// the `default` principal; ordinary principal-home migration deliberately
/// excludes every `.local/audit` subtree. An additional non-default source is
/// therefore a hard migration conflict rather than something that may be
/// silently left mounted or copied as ordinary home data.
#[cfg(unix)]
pub(crate) fn preflight_legacy_audit_sources(
home: &astrid_core::dirs::AstridHome,
default_source: &Path,
) -> std::io::Result<bool> {
let root = home.home_dir();
let metadata = match std::fs::symlink_metadata(&root) {
Ok(metadata) if metadata.file_type().is_symlink() || !metadata.is_dir() => {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
format!(
"legacy principal-home root is not a directory: {}",
root.display()
),
));
},
Ok(metadata) => metadata,
Err(error) if error.kind() == std::io::ErrorKind::NotFound => return Ok(false),
Err(error) => return Err(error),
};
let root_device = audit_tree_device(&metadata);
let mut default_source_present = false;
astrid_core::platform_fs::verify_no_redirects(&root)?;
for entry in std::fs::read_dir(&root)? {
let entry = entry?;
let principal_root = entry.path();
let principal_metadata = std::fs::symlink_metadata(&principal_root)?;View on GitHub (pinned to affd8760f4)