astrid-runtime/astrid · error

workspace tree contains a redirected or special entry: {}

Error message

workspace tree contains a redirected or special entry: {}

What it means

verify_tree walks the workspace tree and rejects any entry that is a symlink, is neither a regular file nor a directory, or whose canonicalized path differs from its walked path. This InvalidInput guards against symlink-based escapes and special files (FIFOs, devices, sockets) appearing inside the workspace, which could redirect reads/writes outside the trusted root.

Source

Thrown at crates/astrid-core/src/workspace_security.rs:151

    /// Returns an error if the root is unsafe, any descendant is a symlink,
    /// reparse redirect, or special file, or the tree changes while walking.
    pub fn verify_tree(&self, relative: impl AsRef<Path>) -> io::Result<PathBuf> {
        let relative = relative.as_ref();
        let root = self.resolve_directory(relative)?;
        if !root.exists() {
            return Ok(root);
        }
        let mut pending = vec![root.clone()];
        while let Some(dir) = pending.pop() {
            for entry in std::fs::read_dir(&dir)? {
                let entry = entry?;
                let path = entry.path();
                let metadata = std::fs::symlink_metadata(&path)?;
                if metadata.file_type().is_symlink()
                    || (!metadata.is_dir() && !metadata.is_file())
                    || std::fs::canonicalize(&path)? != path
                {
                    return Err(io::Error::new(
                        io::ErrorKind::InvalidInput,
                        format!(
                            "workspace tree contains a redirected or special entry: {}",
                            path.display()
                        ),
                    ));
                }
                if metadata.is_dir() {
                    pending.push(path);
                }
            }
        }
        self.resolve_directory(relative)?;
        Ok(root)
    }

    fn resolve_descendant(&self, relative: &Path, kind: DescendantKind) -> io::Result<PathBuf> {
        self.verify()?;

View on GitHub (pinned to affd8760f4)

Solutions

  1. Remove or replace symlinks inside the workspace tree with real files/directories or copies.
  2. Delete or relocate special files (FIFOs, sockets, device nodes) out of the workspace.
  3. Find the offending entry named in the error and check why it canonicalizes elsewhere (readlink/find -type l).
  4. Configure tools that create links (package managers, build scripts) to use copies or hardlink-free modes within the workspace.

Example fix

// before: workspace contains a symlink
// mylib -> /opt/shared/mylib
// after
git rm mylib
cp -rL /opt/shared/mylib mylib  # materialize a real copy
Defensive patterns

Strategy: validation

Validate before calling

fn tree_clean(dir: &Path) -> std::io::Result<()> {
    for entry in std::fs::read_dir(dir)? {
        let p = entry?.path();
        let m = std::fs::symlink_metadata(&p)?;
        if m.file_type().is_symlink() || (!m.is_dir() && !m.is_file()) {
            return Err(io::Error::new(io::ErrorKind::InvalidInput, "bad entry"));
        }
        if m.is_dir() { tree_clean(&p)?; }
    }
    Ok(())
}

Prevention

When it happens

Trigger: Calling verify (or an operation that validates the tree) when the workspace contains a symlink, a FIFO/socket/device, or any entry whose canonical path diverges (e.g. a hardlinked bind or a path containing '..' resolved through a symlinked parent).

Common situations: Checkouts that include symlinked dependencies (node_modules links, vendored symlinks); build systems creating FIFOs; a colleague or tool commiting symlinks pointing outside the repo; mounts appearing inside the tree during validation.

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


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