{"record":{"id":"b132b2c71fe60b24","repo":"astrid-runtime/astrid","slug":"inspect-projected-file-error","errorCode":null,"errorMessage":"inspect projected file {}: {error}","messagePattern":"inspect projected file (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-kernel/src/lib.rs","lineNumber":1670,"sourceCode":"                        \"capsule projection contains a special file: {}\",\n                        path.display()\n                    );\n                }\n            }\n            Ok(())\n        }\n\n        let mut inventory = ProjectionInventory::default();\n        walk(root, root, &mut inventory)?;\n        Ok(inventory)\n    }\n\n    #[cfg(not(all(target_arch = \"wasm32\", target_os = \"unknown\")))]\n    fn read_projection_file_nofollow(path: &Path) -> anyhow::Result<Vec<u8>> {\n        use std::io::Read as _;\n\n        let metadata = std::fs::symlink_metadata(path).map_err(|error| {\n            anyhow::anyhow!(\"inspect projected file {}: {error}\", path.display())\n        })?;\n        if metadata.file_type().is_symlink() || !metadata.is_file() {\n            anyhow::bail!(\n                \"projected path is redirected or not a regular file: {}\",\n                path.display()\n            );\n        }\n        let mut file = open_projection_file_nofollow(path)?;\n        let mut bytes = Vec::new();\n        file.read_to_end(&mut bytes)\n            .map_err(|error| anyhow::anyhow!(\"read projected file {}: {error}\", path.display()))?;\n        if file.metadata()?.len() != metadata.len() || bytes.len() as u64 != metadata.len() {\n            anyhow::bail!(\"projected file changed while read: {}\", path.display());\n        }\n        Ok(bytes)\n    }\n\n    /// Load a capsule into the Kernel from a directory containing a Capsule.toml","sourceCodeStart":1652,"sourceCodeEnd":1688,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-kernel/src/lib.rs#L1652-L1688","documentation":"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.","triggerScenarios":"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.","commonSituations":"Projection root changed underneath a running read; wrong path computed from inventory; permissions tightened on the file; flaky network filesystem.","solutions":["Verify the path exists and is accessible before reading (the inventory path is authoritative).","Retry the read if the file was concurrently replaced or removed.","Check file permissions and ownership on the projection.","Inspect the wrapped io::Error source for the exact OS reason."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"let meta = std::fs::symlink_metadata(path)?;\nanyhow::ensure!(meta.is_file(), \"not a regular file: {}\", path.display());","typeGuard":"fn is_regular_file_nofollow(p: &Path) -> bool {\n    std::fs::symlink_metadata(p).map(|m| m.is_file()).unwrap_or(false)\n}","tryCatchPattern":"match read_projection_file_nofollow(path) {\n    Err(e) if e.to_string().contains(\"inspect projected file\") => {\n        // path vanished or unreadable: re-derive from inventory or retry\n    }\n    other => other,\n}","preventionTips":["Re-read the inventory instead of caching absolute paths.","Check symlink_metadata before direct reads.","Watch for TOCTOU races with concurrent writers."],"tags":["filesystem","io","rust","symlink"],"backgroundTag":"file-open-failed","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}