astrid-runtime/astrid · error
legacy capsule directory is not a regular directory: {}
Error message
legacy capsule directory is not a regular directory: {} What it means
migrate_native_capsules_with_report inspects the legacy native capsule directory (~/.astrid/native or similar) before migrating. If that root path exists but is a symlink or not a regular directory, migration aborts instead of migrating through an unexpected filesystem object.
Source
Thrown at crates/astrid-capsule-install/src/storage/migration.rs:109
store: &Arc<RuntimePrincipalStore>,
home: &astrid_core::dirs::AstridHome,
principal: &PrincipalId,
workspace_targets: &[std::path::PathBuf],
) -> anyhow::Result<LegacyCapsuleMigrationReport> {
let uid = store
.principal_directory()
.uid_for(principal)
.with_context(|| format!("resolve durable uid for principal {principal}"))?;
let native = home.principal_home(principal).capsules_dir();
let metadata = match fs::symlink_metadata(&native) {
Ok(metadata) => metadata,
Err(error) if error.kind() == io::ErrorKind::NotFound => {
return Ok(LegacyCapsuleMigrationReport::default());
},
Err(error) => return Err(error).with_context(|| format!("inspect {}", native.display())),
};
if metadata.file_type().is_symlink() || !metadata.is_dir() {
bail!(
"legacy capsule directory is not a regular directory: {}",
native.display()
);
}
astrid_core::platform_fs::verify_no_redirects(&native)
.with_context(|| format!("verify legacy capsule root {}", native.display()))?;
let mut children = read_dir_sorted(&native)?;
let mut report = LegacyCapsuleMigrationReport::default();
let registry = store.capsules();
let owner = StateOwner::Principal(uid);
for (target, target_metadata) in children.drain(..) {
if target_metadata.file_type().is_symlink() || !target_metadata.is_dir() {
bail!(
"legacy capsule entry is not a regular directory: {}",
target.display()
);
}
let id = targetView on GitHub (pinned to affd8760f4)
Solutions
- Remove the symlink/file at the native path and restore a real directory
- Move the real data into the expected directory location directly
- Point the home/config setting at the actual directory instead of symlinking
- Restore the directory from backup with directory type preserved
Example fix
# before ln -s ~/Dropbox/astrid-native ~/.astrid/native # after mv ~/Dropbox/astrid-native/* ~/.astrid/native/ # real directory, no symlink
Defensive patterns
Strategy: validation
Validate before calling
use std::fs;
fn native_root_is_plain_dir(p: &Path) -> Result<(), String> {
let md = fs::symlink_metadata(p).map_err(|e| e.to_string())?;
if md.file_type().is_symlink() { return Err("symlink".into()); }
if !md.is_dir() { return Err("not a directory".into()); }
Ok(())
} Type guard
fn is_plain_directory(p: &std::path::Path) -> bool {
match std::fs::symlink_metadata(p) {
Ok(md) => md.is_dir() && !md.file_type().is_symlink(),
Err(_) => false,
}
} Try / catch
match migrate_native_capsules(home, store) {
Err(e) if e.to_string().contains("not a regular directory") => {
eprintln!("fix the native capsule path (remove symlink/file) and retry");
}
other => other?,
} Prevention
- Do not symlink the native capsule directory into sync folders or network drives
- Keep backups that preserve directory types
- Check the home path configuration if the root unexpectedly exists as a file
- Run migration before installing any symlinked dev capsules
When it happens
Trigger: The native capsule directory is a symlink (e.g. pointed at Dropbox/Network drive or another location), a plain file was created at that path, or a mount/hardlink oddity replaced the directory.
Common situations: User symlinked their config/data directory into a sync folder; backup tool restored the path as a file; automount points presenting a non-directory node.
Related errors
- legacy capsule entry is not a regular directory: {}
- legacy audit source 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/0d7a4a548f3d9718.
Report an issue: GitHub.