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

  1. Remove the symlink and place the real directory (or a copy/move of its contents) at the legacy state source path, then retry retirement
  2. Investigate who created the link: check deployment scripts, backup/restore tooling, and container image steps for symlink creation at that path
  3. If the tree was legitimately moved, update the library's configured state path instead of linking the old location
  4. 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

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


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