astrid-runtime/astrid · error

legacy state source contains a special file

Error message

legacy state source contains a special file: {}

What it means

Thrown when an entry inside the legacy state source tree is neither a directory nor a regular file — e.g. a FIFO, socket, or device node. Only plain files and directories are safe to validate and delete, so anything else aborts retirement with InvalidData before any data is removed.

Solutions

  1. Identify the entry (stat shows its type) and remove it — special files have no data relevant to retirement (rm on a fifo/socket removes only the node)
  2. Stop or relocate any process that creates sockets/pipes inside the state directory, so it stays regular-files-only
  3. Re-run retirement once the tree contains only regular files and directories

Example fix

# before: a fifo/socket inside the legacy tree
/srv/astrid/var/state/surrealkv/control.sock (socket)
# after: remove the node and re-run
rm /srv/astrid/var/state/surrealkv/control.sock
# restart the daemon with its socket path outside the state tree
Defensive patterns

Strategy: validation

Validate before calling

fn tree_has_special_files(root: &Path) -> std::io::Result<Vec<std::path::PathBuf>> {
    let mut found = Vec::new();
    for entry in std::fs::read_dir(root)? {
        let child = entry?.path();
        let meta = std::fs::symlink_metadata(&child)?;
        if meta.is_dir() {
            found.extend(tree_has_special_files(&child)?);
        } else if !meta.is_file() {
            found.push(child);
        }
    }
    Ok(found)
}

Type guard

fn is_special_entry(path: &Path) -> bool {
    match std::fs::symlink_metadata(path) {
        Ok(m) => !m.is_dir() && !m.is_file(),
        Err(_) => false,
    }
}

Try / catch

match retire_legacy_source_tree(&path) {
    Err(e) if e.to_string().contains("special file") => {
        // remove the fifo/socket/device node, then retry retirement
    }
    other => other?,
}

Prevention

When it happens

Trigger: validate_legacy_tree recursion hits a child whose symlink_metadata shows it is not a symlink, not a directory, and not a file — a FIFO left by a tool, a unix socket created by a process using the state dir, a device node from a bad restore, or a race that swapped the entry type mid-walk.

Common situations: A process (e.g. an embedded daemon) created a socket/FIFO inside the legacy state directory; corrupted or partial backup restores containing special files; tmpfs or devtooling artifacts; tests that leaked fifos into the state path.

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

Appendix: source

Thrown at crates/astrid-core/src/dirs_layout_retirement.rs:78

        let child_metadata = std::fs::symlink_metadata(&child)?;
        if child_metadata.file_type().is_symlink() {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!(
                    "legacy state source contains a redirect: {}",
                    child.display()
                ),
            ));
        }
        ensure_legacy_tree_boundary(&child, root_device, &child_metadata)?;
        if child_metadata.is_dir() {
            validate_legacy_tree(&child, root_device)?;
        } else if child_metadata.is_file() {
            // Opening only after the no-follow validation ensures a replaced
            // symlink is rejected rather than read or removed through it.
            crate::platform_fs::verify_no_redirects(&child)?;
        } else {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!(
                    "legacy state source contains a special file: {}",
                    child.display()
                ),
            ));
        }
    }
    Ok(())
}

pub(super) fn delete_legacy_tree(path: &Path, root_device: u64) -> io::Result<()> {
    let metadata = match std::fs::symlink_metadata(path) {
        Ok(metadata) => metadata,
        Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(()),
        Err(error) => return Err(error),
    };
    if metadata.file_type().is_symlink() || !metadata.is_dir() {

View on GitHub (pinned to affd8760f4)