astrid-runtime/astrid · error
legacy state source is redirected: {}
Error message
legacy state source is redirected: {} What it means
This error is thrown during no-follow retirement of the legacy directory-backed state tree when the source path itself is a symlink. The library deliberately refuses to operate through symlinks so a malicious or accidental redirection cannot cause validation or deletion to act on a different tree. It reports InvalidData with the offending path.
Source
Thrown at crates/astrid-core/src/dirs_layout_retirement.rs:43
validate_legacy_tree(path, legacy_tree_device(&metadata))
}
#[cfg(unix)]
pub(super) fn legacy_tree_device(metadata: &std::fs::Metadata) -> u64 {
use std::os::unix::fs::MetadataExt as _;
metadata.dev()
}
#[cfg(not(unix))]
pub(super) fn legacy_tree_device(_metadata: &std::fs::Metadata) -> u64 {
0
}
pub(super) fn validate_legacy_tree(path: &Path, root_device: u64) -> io::Result<()> {
let metadata = std::fs::symlink_metadata(path)?;
if metadata.file_type().is_symlink() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("legacy state source is redirected: {}", path.display()),
));
}
if !metadata.is_dir() {
return Err(io::Error::new(
io::ErrorKind::InvalidData,
format!("legacy state source is not a directory: {}", path.display()),
));
}
crate::platform_fs::verify_no_redirects(path)?;
ensure_legacy_tree_boundary(path, root_device, &metadata)?;
for entry in std::fs::read_dir(path)? {
let entry = entry?;
let child = entry.path();
let child_metadata = std::fs::symlink_metadata(&child)?;
if child_metadata.file_type().is_symlink() {View on GitHub (pinned to affd8760f4)
Solutions
- Remove the symlink and place the real directory (or a copy/move of its contents) at the legacy state source path, then retry retirement
- Investigate who created the link: check deployment scripts, backup/restore tooling, and container image steps for symlink creation at that path
- If the tree was legitimately moved, update the library's configured state path instead of linking the old location
- Re-run retirement; the operation is idempotent and validation fails fast before anything is deleted
Example fix
// before: legacy state path is a symlink ln -s /mnt/shared/legacy-state /srv/astrid/var/state // after: use a real directory (bind mount or move, not a symlink) mv /mnt/shared/legacy-state /srv/astrid/var/state # or mount --bind
Defensive patterns
Strategy: validation
Validate before calling
fn is_real_dir(path: &Path) -> std::io::Result<bool> {
let meta = std::fs::symlink_metadata(path)?;
Ok(meta.is_dir() && !meta.file_type().is_symlink())
}
// call before retirement: if !is_real_dir(&legacy_path)? { fix layout first } Type guard
fn is_symlink(path: &Path) -> bool {
std::fs::symlink_metadata(path)
.map(|m| m.file_type().is_symlink())
.unwrap_or(false)
} Try / catch
match retire_legacy_source_tree(&path) {
Err(e) if e.kind() == std::io::ErrorKind::InvalidData && e.to_string().contains("redirected") => {
// resolve the symlink, restore a real directory, retry
}
other => other?,
} Prevention
- Never symlink state directories; use bind mounts or update the configured path instead
- Audit deployment and restore scripts for ln -s targeting the state tree
- Check with symlink_metadata (not metadata) when pre-validating state paths so links are caught
When it happens
Trigger: Calling retire_legacy_source_tree or validate_legacy_retirement_candidate where the legacy state source path has been replaced by (or was created as) a symlink; symlink_metadata reports a symlink file type at validate_legacy_tree. Also reachable when an interior directory was swapped for a symlink between listing and recursion (validate_legacy_tree recursing into a child).
Common situations: Operators replacing the legacy state directory with a symlink to shared/network storage; packaging or deployment tooling that creates convenience symlinks into state directories; restore scripts that link rather than move data back; concurrent tampering during retirement.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- legacy state source contains a redirect: {}
- directory symlink {} not allowed in capsule source tree (ref
- inspect projected file {}: {error}
- legacy state source changed type: {}
- private path is redirected: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/b57d6eddd0803db7.
Report an issue: GitHub.