astrid-runtime/astrid · error
cache changed to a redirect or special entry: {}
Error message
cache changed to a redirect or special entry: {} What it means
remove_cache_tree in astrid-capsule-install refuses to delete a materialization-cache path whose symlink_metadata shows it is a symlink or neither a directory nor a regular file (e.g. fifo, device, socket). The library treats symlinks and special files as 'redirects' that could point outside the cache, so instead of following/removing them blindly it bails to protect against path-redirect attacks or corrupted cache state. The word 'changed' indicates a TOCTOU check: the entry was expected to be a plain dir/file but mutated between validation and removal.
Source
Thrown at crates/astrid-capsule-install/src/paths.rs:227
"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()) {
anyhow::bail!(
"cache changed to a redirect or special entry: {}",
path.display()
);
}
if metadata.is_dir() {
for entry in std::fs::read_dir(path).with_context(|| format!("read {}", path.display()))? {
remove_cache_tree(
&entry
.with_context(|| format!("read cache entry under {}", path.display()))?
.path(),
)?;
}
std::fs::remove_dir(path).with_context(|| format!("remove {}", path.display()))?;
} else {
std::fs::remove_file(path).with_context(|| format!("remove {}", path.display()))?;
}
Ok(())
}View on GitHub (pinned to affd8760f4)
Solutions
- Inspect the reported path with `ls -la` and replace the symlink/special file with a real directory or file (or remove it yourself) before re-running.
- Clear the offending entry manually (`rm` the symlink, `mkfifo`/socket leftovers) and let the tool rebuild the cache.
- Stop processes that write into the cache concurrently so entries cannot be swapped mid-removal.
- If symlinking the cache is intentional, it is unsupported: relocate the whole Astrid home instead of individual cache entries.
Example fix
// before: symlinked cache entry pointing to another disk ln -s /mnt/bigdisk/astrid-cache/entry ~/.astrid/cache/entry clear_capsule_materialization_cache(...) // -> cache changed to a redirect or special entry // after: remove the symlink and let the tool own the path rm ~/.astrid/cache/entry mkdir ~/.astrid/cache/entry
Defensive patterns
Strategy: validation
Validate before calling
let md = std::fs::symlink_metadata(path)?;
if md.file_type().is_symlink() || (!md.is_dir() && !md.is_file()) {
// resolve before invoking the cache-clearing API
eprintln!("cache entry {} is a redirect/special file; fix manually", path.display());
} Type guard
fn is_plain_entry(md: &std::fs::Metadata) -> bool {
!md.file_type().is_symlink() && (md.is_dir() || md.is_file())
} Try / catch
match clear_capsule_materialization_cache() {
Err(e) if e.to_string().contains("redirect or special entry") => {
// repair path manually or wipe the cache root, then retry once
}
other => other?,
} Prevention
- Never symlink individual entries inside the Astrid cache; relocate the whole home instead
- Do not let build tools create fifos/sockets inside the cache directory
- Avoid concurrent processes mutating the same cache tree
- Restore caches as real files/dirs, not symlinks
When it happens
Trigger: Calling clear_capsule_materialization_cache (which recurses remove_cache_tree) while a cache entry is a symlink to elsewhere, or a special file (fifo/socket/device). Also fires if another process or attacker swaps a real cache entry for a symlink between the validate_cache_tree pass and the removal pass.
Common situations: Manual tinkering with the Astrid home cache directory (e.g. ln -s to move a large cache to another disk); a build tool creating fifos/sockets inside the cache; concurrent runs of the tool racing on the same cache tree; restored-from-backup caches containing symlinks.
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
- 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: {}
- directory symlink {} not allowed in capsule source tree (ref
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/c108951ff1414c7e.
Report an issue: GitHub.