astrid-runtime/astrid · error

inspect projected file {}: {error}

Error message

inspect projected file {}: {error}

What it means

Thrown by `read_projection_file_nofollow` when `symlink_metadata` on a projected file path fails. The function reads projected files without following symlinks and must first confirm the path is a regular file; failing to stat it aborts the read. The OS error is wrapped with the path.

Source

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

                        "capsule projection contains a special file: {}",
                        path.display()
                    );
                }
            }
            Ok(())
        }

        let mut inventory = ProjectionInventory::default();
        walk(root, root, &mut inventory)?;
        Ok(inventory)
    }

    #[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
    fn read_projection_file_nofollow(path: &Path) -> anyhow::Result<Vec<u8>> {
        use std::io::Read as _;

        let metadata = std::fs::symlink_metadata(path).map_err(|error| {
            anyhow::anyhow!("inspect projected file {}: {error}", path.display())
        })?;
        if metadata.file_type().is_symlink() || !metadata.is_file() {
            anyhow::bail!(
                "projected path is redirected or not a regular file: {}",
                path.display()
            );
        }
        let mut file = open_projection_file_nofollow(path)?;
        let mut bytes = Vec::new();
        file.read_to_end(&mut bytes)
            .map_err(|error| anyhow::anyhow!("read projected file {}: {error}", path.display()))?;
        if file.metadata()?.len() != metadata.len() || bytes.len() as u64 != metadata.len() {
            anyhow::bail!("projected file changed while read: {}", path.display());
        }
        Ok(bytes)
    }

    /// Load a capsule into the Kernel from a directory containing a Capsule.toml

View on GitHub (pinned to affd8760f4)

Solutions

  1. Verify the path exists and is accessible before reading (the inventory path is authoritative).
  2. Retry the read if the file was concurrently replaced or removed.
  3. Check file permissions and ownership on the projection.
  4. Inspect the wrapped io::Error source for the exact OS reason.
Defensive patterns

Strategy: validation

Validate before calling

let meta = std::fs::symlink_metadata(path)?;
anyhow::ensure!(meta.is_file(), "not a regular file: {}", path.display());

Type guard

fn is_regular_file_nofollow(p: &Path) -> bool {
    std::fs::symlink_metadata(p).map(|m| m.is_file()).unwrap_or(false)
}

Try / catch

match read_projection_file_nofollow(path) {
    Err(e) if e.to_string().contains("inspect projected file") => {
        // path vanished or unreadable: re-derive from inventory or retry
    }
    other => other,
}

Prevention

When it happens

Trigger: Reading a projected file whose path does not exist, is unreadable, or whose lstat fails due to IO error; race where the file is deleted just before reading.

Common situations: Projection root changed underneath a running read; wrong path computed from inventory; permissions tightened on the file; flaky network filesystem.

Understand the failure class

Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.

Related errors


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