astrid-runtime/astrid · error

cache contains a redirect or special entry: {}

Error message

cache contains a redirect or special entry: {}

What it means

validate_cache_tree recursively walks the materialization cache and rejects any entry that is a symlink or neither a directory nor a regular file (fifos, sockets, devices). This enforces that the cache tree contains only plain materialized content, protecting against redirect attacks and special files inside a tree that will later be deleted or executed from. It recurses into subdirectories and is also called by itself.

Source

Thrown at crates/astrid-capsule-install/src/paths.rs:208

        let path = entry
            .context("read capsule materialization cache entry")?
            .path();
        remove_cache_tree(&path)?;
    }
    Ok(())
}

fn validate_cache_tree(path: &Path) -> anyhow::Result<()> {
    astrid_core::platform_fs::verify_no_redirects(path)
        .with_context(|| format!("verify cache path {}", path.display()))?;
    for entry in std::fs::read_dir(path).with_context(|| format!("read {}", path.display()))? {
        let path = entry
            .with_context(|| format!("read cache entry under {}", path.display()))?
            .path();
        let metadata = std::fs::symlink_metadata(&path)
            .with_context(|| format!("inspect {}", path.display()))?;
        if metadata.file_type().is_symlink() || (!metadata.is_dir() && !metadata.is_file()) {
            anyhow::bail!(
                "cache contains a redirect or special entry: {}",
                path.display()
            );
        }
        if metadata.is_dir() {
            validate_cache_tree(&path)?;
        } else {
            astrid_core::platform_fs::verify_no_redirects(&path)
                .with_context(|| format!("verify cache file {}", path.display()))?;
        }
    }
    Ok(())
}

fn remove_cache_tree(path: &Path) -> anyhow::Result<()> {
    let metadata = std::fs::symlink_metadata(path)
        .with_context(|| format!("inspect cache path {}", path.display()))?;
    if metadata.file_type().is_symlink() || (!metadata.is_dir() && !metadata.is_file()) {

View on GitHub (pinned to affd8760f4)

Solutions

  1. Inspect the reported path (`ls -la`) and delete the offending symlink/special entry, then re-run the cleanup
  2. Purge and rebuild the whole cache directory after verifying the root itself is safe
  3. Find the process that created the non-regular entry and stop it from writing into the cache
  4. Restrict write access to the cache directory to the runtime user only

Example fix

// before
$ find ~/.cache/astrid/capsules -type l   # shows link -> /etc
// after
$ rm ~/.cache/astrid/capsules/<offending-link>
# or full reset:
$ rm -rf ~/.cache/astrid/capsules && mkdir ~/.cache/astrid/capsules
Defensive patterns

Strategy: validation

Validate before calling

fn cache_tree_has_only_regular_entries(root: &Path) -> anyhow::Result<bool> {
    for entry in std::fs::read_dir(root)? {
        let p = entry?.path();
        let m = std::fs::symlink_metadata(&p)?;
        if m.file_type().is_symlink() || (!m.is_dir() && !m.is_file()) {
            return Ok(false);
        }
        if m.is_dir() && !cache_tree_has_only_regular_entries(&p)? { return Ok(false); }
    }
    Ok(true)
}

Type guard

fn is_plain_entry(p: &Path) -> bool {
    std::fs::symlink_metadata(p).map(|m| !m.file_type().is_symlink() && (m.is_dir() || m.is_file())).unwrap_or(false)
}

Try / catch

if let Err(e) = clear_capsule_materialization_cache(&root) {
    if e.to_string().contains("redirect or special entry") {
        // extract the offending path, delete it, retry
    } else { return Err(e); }
}

Prevention

When it happens

Trigger: A symlink planted inside the cache (e.g. pointing to /etc) or a socket/fifo/device node appearing under the cache root when clear_capsule_materialization_cache calls validate_cache_tree, or when validate_cache_tree is invoked recursively.

Common situations: Malicious or curious tooling creating links inside the shared cache directory; build processes that leave sockets/fifos in cache paths; restored-from-backup caches containing symlinks; crash residue from another program.

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/46ebc24f2b72f0fe. Report an issue: GitHub.