astrid-runtime/astrid · error
legacy principal home root is not a regular directory: {}
Error message
legacy principal home root is not a regular directory: {} What it means
Thrown by admit_unbound_legacy_principal_homes when the legacy principal home root exists but is not a regular directory — it is a symlink or another file type. Migration refuses to scan or adopt content from anything that could be a redirect or non-directory, to avoid following links outside the trusted tree. A NotFound error is deliberately tolerated (nothing to migrate); a wrong-type existing path is not.
Source
Thrown at crates/astrid-kernel/src/principal_home_migration/unbound.rs:38
const QUARANTINE_DIR: &str = "unbound-legacy-homes";
/// Mint identities for leftover valid aliases and quarantine invalid names.
///
/// Call this only on the first layout-1 cut-over, before the barrier snapshots
/// admitted bindings. Existing-v2 leftover sources still fail closed later.
pub(crate) async fn admit_unbound_legacy_principal_homes(
home: &AstridHome,
directory: &PrincipalDirectory,
identity: &dyn IdentityStore,
) -> io::Result<()> {
let source_root = home.home_dir();
let metadata = match fs::symlink_metadata(&source_root) {
Ok(metadata) => metadata,
Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(()),
Err(error) => return Err(error),
};
if metadata.file_type().is_symlink() || !metadata.is_dir() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!(
"legacy principal home root is not a regular directory: {}",
source_root.display()
),
));
}
astrid_core::platform_fs::ensure_private_directory_tree(&source_root)?;
astrid_core::platform_fs::verify_no_redirects(&source_root)?;
let mut entries = Vec::new();
for entry in fs::read_dir(&source_root).map_err(|error| {
io::Error::new(
error.kind(),
format!("scan {}: {error}", source_root.display()),
)
})? {
entries.push(entry?);View on GitHub (pinned to affd8760f4)
Solutions
- Replace the symlink/non-directory at the legacy home path with a real directory containing the legacy principal homes.
- Point migration's source_root configuration at the actual legacy directory rather than a link to it.
- Check mount points and restores: ensure the expected directory structure exists at the configured path.
- Remove any stale non-directory placeholder and re-run migration.
Example fix
// before mv ~/.legacy-homes ~/.legacy-homes-real ln -s ~/.legacy-homes-real ~/.legacy-homes // symlink is rejected // after rm ~/.legacy-homes mv ~/.legacy-homes-real ~/.legacy-homes // real directory
Defensive patterns
Strategy: validation
Validate before calling
fn legacy_root_ok(path: &Path) -> bool {
match fs::symlink_metadata(path) {
Ok(m) => !m.file_type().is_symlink() && m.is_dir(),
Err(e) => e.kind() == io::ErrorKind::NotFound, // tolerated: nothing to migrate
}
} Try / catch
match admit_unbound_legacy_principal_homes(&source_root, ...) {
Ok(()) => (),
Err(e) if e.to_string().contains("not a regular directory") => {
// replace symlink/file with a real directory, then retry
return Err(e.into_config_error("fix legacy home root path"));
}
Err(e) => return Err(e),
} Prevention
- Ensure the legacy home root is a real directory, never a symlink.
- Point configuration at actual directories, not links to them.
- Check for symlinks in the migration path (find -type l) before starting.
- After restores, verify directory structure and types match expectations.
When it happens
Trigger: admit_unbound_legacy_principal_homes calls fs::symlink_metadata on the legacy home root and finds is_symlink() true or is_dir() false (regular file, FIFO, device node, etc.).
Common situations: The legacy home path was replaced by a symlink to relocate storage; the path points at a regular file due to a botched copy/restore; a container or mount maps the home path to a non-directory.
Related errors
- legacy principal profile is not a regular file: {}
- layout migration destination is redirected or not a regular
- layout migration source is redirected or not a directory: {}
- legacy state source is redirected: {}
- legacy state source contains a redirect: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/fc1f14aa25c7f9d6.
Report an issue: GitHub.