astrid-runtime/astrid · error

read capsule projection {}: {error}

Error message

read capsule projection {}: {error}

What it means

Thrown by the projection inventory `walk` helper when `std::fs::read_dir` on a capsule projection directory fails. The directory could not be listed at all, so the inventory cannot be built. The OS error is wrapped with the directory path for diagnosis.

Source

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

        let digest = blake3::hash(&snapshot.package().archive)
            .to_hex()
            .to_string();
        if components[2] != digest {
            anyhow::bail!("materialized capsule digest does not match durable registry");
        }
        Ok(())
    }

    /// Inventory a projection without traversing redirects or special files.
    #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
    fn inventory_projection_files(root: &Path) -> anyhow::Result<ProjectionInventory> {
        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()

View on GitHub (pinned to affd8760f4)

Solutions

  1. Ensure the projection directory exists and is materialized before invoking the inventory walk.
  2. Check filesystem permissions on the directory (read/execute bits).
  3. Confirm the configured projection root path is correct and is a directory.
  4. Inspect the wrapped io::Error source for the exact OS reason (ENOENT, EACCES, ENOTDIR).

Example fix

// before
inventory::walk(&root, &root, &mut inv)?; // fails if root missing
// after
assert!(root.is_dir(), "projection root must exist: {}", root.display());
inventory::walk(&root, &root, &mut inv)?;
Defensive patterns

Strategy: validation

Validate before calling

if !dir.is_dir() {
    anyhow::bail!("projection directory missing: {}", dir.display());
}

Type guard

fn is_listable_dir(p: &Path) -> bool { p.is_dir() && std::fs::read_dir(p).is_ok() }

Try / catch

match walk_inventory(root) {
    Err(e) if e.to_string().contains("read capsule projection") => retry_or_rematerialize(root),
    Err(e) => return Err(e),
    Ok(inv) => Ok(inv),
}

Prevention

When it happens

Trigger: Calling the projection inventory/walk code against a directory path that does not exist, is not a directory, or is unreadable due to permissions.

Common situations: Projection root deleted or not yet materialized before walking; wrong mount path in config; permission changes on the projection directory; passing a file path instead of a directory.

Related errors


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