astrid-runtime/astrid · error
legacy env/secret path is not a regular directory: {}
Error message
legacy env/secret path is not a regular directory: {} What it means
While checking whether legacy env/secret entries exist, the code stats the path with symlink_metadata and requires it to be a real (non-symlink) directory. If the path is a symlink or any non-directory file type, it bails with this error rather than silently treating it as present or absent. This protects against hostile or accidental symlinks pointing the legacy importer at unexpected locations.
Source
Thrown at crates/astrid-capsule-install/src/storage/migration.rs:347
statuses.push(LegacyEnvSecretImportStatus {
uid,
alias,
native_env_present,
native_secret_present,
unreceipted_capsules,
});
}
Ok(statuses)
}
fn legacy_entries_present(path: &Path) -> anyhow::Result<bool> {
let metadata = match fs::symlink_metadata(path) {
Ok(metadata) => metadata,
Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(false),
Err(error) => return Err(error).with_context(|| format!("inspect {}", path.display())),
};
if metadata.file_type().is_symlink() || !metadata.is_dir() {
bail!(
"legacy env/secret path is not a regular directory: {}",
path.display()
);
}
let mut entries = fs::read_dir(path).with_context(|| format!("read {}", path.display()))?;
Ok(entries.next().transpose()?.is_some())
}
#[cfg(test)]
mod tests {
use std::sync::Arc;
use astrid_core::identity::PrincipalUid;
use astrid_storage::{
KvQuotaResolver, PrincipalDirectory, StateOwner,
open_runtime_principal_store_with_directory,
};
View on GitHub (pinned to affd8760f4)
Solutions
- Replace the symlink with a real directory (move the symlink's target contents into place, or remove the symlink and re-create the directory).
- If it is a regular file, remove or rename it and recreate the expected directory.
- Re-run the import after the path is a plain directory.
Example fix
// before: legacy path is a symlink → bail ~/.astrid/legacy/env -> /mnt/dotfiles/env // after: make it a real directory rm ~/.astrid/legacy/env mkdir -p ~/.astrid/legacy/env cp -a /mnt/dotfiles/env/. ~/.astrid/legacy/env/
Defensive patterns
Strategy: validation
Validate before calling
let meta = std::fs::symlink_metadata(path)?;
if meta.file_type().is_symlink() || !meta.is_dir() {
eprintln!("{} must be a real directory; fix before import", path.display());
} Type guard
fn is_regular_dir(path: &std::path::Path) -> bool {
std::fs::symlink_metadata(path)
.map(|m| m.is_dir() && !m.file_type().is_symlink())
.unwrap_or(false)
} Try / catch
match import_env_and_secrets(&home, &directory) {
Ok(s) => { /* ... */ }
Err(e) if e.to_string().contains("not a regular directory") => {
eprintln!("replace the symlink/file at the legacy path with a real directory");
}
Err(e) => return Err(e),
} Prevention
- Do not symlink legacy env/secret directories into dotfile/sync stores.
- Restore from backups as real directories, not symlinks.
- Audit legacy paths with `find -type l` before migration.
- Document that the importer requires plain directories.
When it happens
Trigger: legacy_env_secret_import_status → legacy_entries_present is called and the legacy env/secret path is a symlink, a regular file, a FIFO, etc., instead of an actual directory.
Common situations: Users replaced the legacy directory with a symlink into a synced/Dotfiles-managed location (e.g. ~/dotfiles/env → ~/.astrid/legacy/env); packaging left a regular file where the directory should be; restore tools replaced directories with symlinks.
Related errors
- workspace path must not contain redirects or unexpected file
- workspace state path must be a real directory, not a redirec
- legacy principal-home root is not a directory: {}
- legacy principal-home entry is not a regular directory: {}
- legacy source is not a regular file: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/5398fdd1d68de713.
Report an issue: GitHub.