astrid-runtime/astrid · error

inspect capsule projection {}: {error}

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.

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)

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.