astrid-runtime/astrid · error

inspect capsule projection

Error message

inspect capsule projection {}: {error}

What it means

Thrown when `std::fs::symlink_metadata` fails for an entry in the capsule projection during the inventory walk. The metadata is needed to classify the entry (file/dir/symlink); if it cannot be inspected the walk cannot continue safely. The OS error is wrapped with the path.

Solutions

  1. Retry the inventory walk after the concurrent mutation settles.
  2. Ensure no other process deletes/modifies projection entries during the walk.
  3. Check filesystem health and permissions for the reported path.
  4. Capture the wrapped io::Error source for the exact OS errno.
Defensive patterns

Strategy: retry

Try / catch

match build_inventory(root) {
    Err(e) if e.to_string().contains("inspect capsule projection") => build_inventory(root),
    other => other,
}

Prevention

When it happens

Trigger: The entry vanished between `read_dir` and `symlink_metadata` (TOCTOU race), or lstat fails due to permissions or IO errors on the filesystem.

Common situations: Concurrent deletion during inventory; files on a failing or network mount; permission bits changed mid-walk.

Understand the failure class

Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.

Related errors


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

Appendix: source

Thrown at crates/astrid-kernel/src/lib.rs:1636

        fn walk(
            root: &Path,
            directory: &Path,
            inventory: &mut ProjectionInventory,
        ) -> anyhow::Result<()> {
            for entry in std::fs::read_dir(directory).map_err(|error| {
                anyhow::anyhow!("read capsule projection {}: {error}", directory.display())
            })? {
                let entry = entry
                    .map_err(|error| anyhow::anyhow!("read capsule projection entry: {error}"))?;
                let path = entry.path();
                let relative = path.strip_prefix(root).map_err(|_| {
                    anyhow::anyhow!("capsule projection escaped its root: {}", path.display())
                })?;
                let relative_text = relative.to_str().ok_or_else(|| {
                    anyhow::anyhow!("capsule projection path is not UTF-8: {}", path.display())
                })?;
                let metadata = std::fs::symlink_metadata(&path).map_err(|error| {
                    anyhow::anyhow!("inspect capsule projection {}: {error}", path.display())
                })?;
                let file_type = metadata.file_type();
                if file_type.is_symlink() {
                    anyhow::bail!(
                        "capsule projection contains a symbolic link: {}",
                        path.display()
                    );
                }
                if file_type.is_dir() {
                    inventory.directories.insert(relative_text.to_owned());
                    walk(root, &path, inventory)?;
                } else if file_type.is_file() {
                    inventory.files.insert(relative_text.to_owned());
                } else {
                    anyhow::bail!(
                        "capsule projection contains a special file: {}",
                        path.display()
                    );

View on GitHub (pinned to affd8760f4)