astrid-runtime/astrid · error
projected path is redirected or not a regular file: {}
Error message
projected path is redirected or not a regular file: {} What it means
This error means a projected path failed the read-time safety check: symlink_metadata showed either a symlink (a redirect) or a non-regular file where a regular file was required. The kernel throws it in the per-file read path so it never opens anything that could redirect (TOCTOU via symlink) or block (e.g. a FIFO), and is the single-file counterpart to the projection-wide symlink/special-file checks.
Source
Thrown at crates/astrid-kernel/src/lib.rs:1673
}
}
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
///
/// # Errors
///View on GitHub (pinned to affd8760f4)
Solutions
- Re-materialize the capsule so the projection is rebuilt from the trusted archive with only regular files
- Verify the path passed to the read API is a regular file inside the projection (check symlink_metadata before calling)
- Find and remove whatever replaced the file with a symlink/special file; investigate concurrent writers to the capsule directory
- If packaging produced links/special files, repackage (dereference links, exclude non-regular entries)
Example fix
// before: reading without checking the entry type
let bytes = read_projected_file(&path)?;
// after: pre-check before reading
let meta = std::fs::symlink_metadata(&path)?;
if meta.file_type().is_symlink() || !meta.is_file() {
anyhow::bail!("refusing non-regular projected path: {}", path.display());
}
let bytes = read_projected_file(&path)?; Defensive patterns
Strategy: validation
Validate before calling
let meta = std::fs::symlink_metadata(path)?;
if meta.file_type().is_symlink() || !meta.is_file() {
return Err("projected path must be a regular, non-symlink file");
} Try / catch
match result {
Err(e) if e.to_string().contains("redirected or not a regular file") => {
// re-materialize the projection; treat as a security signal
}
other => other?,
} Prevention
- Pre-check entry type with symlink_metadata before reading
- Never share capsule directories with untrusted writers
- Re-materialize from the trusted archive if the projection was touched
- Treat any symlink appearance in a projection as a potential race/attack
When it happens
Trigger: Reading a projected file (the read_projected_file path used during inventory verification) when metadata.file_type().is_symlink() is true or metadata.is_file() is false — e.g. the entry was replaced by a symlink between inventory and read, or the caller passed a path to a directory/socket/fifo.
Common situations: Concurrent modification of the capsule directory (another process swapping in symlinks); passing the wrong path (a directory) to a file-read API; a projection where a packaging bug left links or special files; an attacker redirecting a projected path via a race.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- capsule projection contains a symbolic link: {}
- leftover capsule authority receipt is not a regular file: {}
- legacy capsule authority root is not a regular directory: {}
- legacy capsule authority root contains a non-regular entry:
- legacy capsule authority root is not a regular directory: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/1bd2ff8a81a7fd9c.
Report an issue: GitHub.