astrid-runtime/astrid · error

legacy capsule entry is not a regular directory: {}

Error message

legacy capsule entry is not a regular directory: {}

What it means

While enumerating children of the legacy native capsule directory, each entry must be a regular directory representing one capsule. If an entry is a symlink or a non-directory file, migration stops with this error rather than guessing how to migrate it.

Source

Thrown at crates/astrid-capsule-install/src/storage/migration.rs:122

            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 = target
            .file_name()
            .and_then(|name| name.to_str())
            .ok_or_else(|| anyhow::anyhow!("legacy capsule entry has a non-UTF-8 name"))?;
        let manifest = astrid_capsule::discovery::load_manifest(&target.join("Capsule.toml"))
            .with_context(|| format!("read legacy capsule manifest {id}"))?;
        if manifest.package.name != id {
            bail!(
                "legacy capsule directory {id} does not match manifest id {}",
                manifest.package.name
            );
        }
        let meta_bytes = fs::read(target.join("meta.json"))
            .with_context(|| format!("read legacy capsule metadata {id}"))?;

View on GitHub (pinned to affd8760f4)

Solutions

  1. Remove the symlink or stray file from the legacy capsules directory
  2. Move the real capsule directory to the expected location instead of linking it
  3. Delete broken/incomplete capsule entries that are not valid directories
  4. Run migration again after the capsules root contains only regular directories

Example fix

# before
~/.astrid/native/my-capsule -> ~/dev/my-capsule (symlink)
# after
cp -a ~/dev/my-capsule ~/.astrid/native/my-capsule  # real directory
Defensive patterns

Strategy: validation

Validate before calling

fn capsules_root_clean(p: &Path) -> Result<(), String> {
    for entry in std::fs::read_dir(p).map_err(|e| e.to_string())? {
        let e = entry.map_err(|e| e.to_string())?;
        let ft = e.file_type().map_err(|e| e.to_string())?;
        if ft.is_symlink() || !ft.is_dir() {
            return Err(format!("{} is not a regular directory", e.path().display()));
        }
    }
    Ok(())
}

Type guard

fn is_regular_dir_entry(p: &std::path::Path) -> bool {
    std::fs::symlink_metadata(p)
        .map(|md| md.is_dir() && !md.file_type().is_symlink())
        .unwrap_or(false)
}

Try / catch

if let Err(e) = migrate_native_capsules(home, store) {
    if e.to_string().contains("entry is not a regular directory") {
        eprintln!("remove symlinks/stray files from the capsules directory, then retry");
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: A symlink inside the native capsules directory (e.g. one capsule symlinked to a dev checkout), or a stray file (log, .DS_Store-like artifact, tarball) sitting directly in the capsules root.

Common situations: Developers symlink their in-development capsule into the installed capsules directory; downloads or editors leave loose files in the capsules root; corrupted partial installs.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/496619554644f538. Report an issue: GitHub.