astrid-runtime/astrid · error · io::Error

layout migration source contains a special file: {}

Error message

layout migration source contains a special file: {}

What it means

The inventory walk only supports plain files and directories inside the migration source. Any other directory entry type (fifo, socket, device node, etc.) makes the tree impossible to fingerprint deterministically, so inventory_directory aborts with InvalidData naming the path. This keeps the migration inventory well-defined across platforms.

Source

Thrown at crates/astrid-core/src/dirs_layout_records.rs:447

                *bytes = bytes
                    .checked_add(read as u64)
                    .ok_or_else(|| io::Error::other("layout inventory byte count overflow"))?;
                file_bytes = file_bytes
                    .checked_add(read as u64)
                    .ok_or_else(|| io::Error::other("layout inventory file length overflow"))?;
                hasher.update(&buffer[..read]);
            }
            if file_bytes != metadata.len() {
                return Err(io::Error::new(
                    io::ErrorKind::InvalidData,
                    format!(
                        "layout migration source changed while inventoried: {}",
                        child_path.display()
                    ),
                ));
            }
        } else {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!(
                    "layout migration source contains a special file: {}",
                    child_path.display()
                ),
            ));
        }
    }
    Ok(())
}

fn hash_inventory_field(hasher: &mut blake3::Hasher, label: &[u8], value: &[u8]) {
    hasher.update(&(label.len() as u64).to_le_bytes());
    hasher.update(label);
    hasher.update(&(value.len() as u64).to_le_bytes());
    hasher.update(value);
}

View on GitHub (pinned to affd8760f4)

Solutions

  1. Stop the application that created the special file (usually a daemon holding a unix socket) so it is cleaned up.
  2. Delete the named fifo/socket/device node if it is stale (it will be recreated on next run).
  3. Verify no device nodes exist: find <state-dir> ! -type f ! -type d and remove/fix the hits.
  4. Re-run the migration once the tree holds only regular files and directories.

Example fix

// before: stale socket blocks migration
$ ls ~/.local/state/astrid/surrealkv.sock   # srwxr-xr-x unix socket
// after: stop the daemon and remove it
$ systemctl --user stop astrid && rm ~/.local/state/astrid/surrealkv.sock && astrid migrate
Defensive patterns

Strategy: validation

Validate before calling

use std::path::Path;
fn assert_only_files_and_dirs(dir: &Path) -> std::io::Result<()> {
    for entry in std::fs::read_dir(dir)? {
        let entry = entry?;
        let ft = std::fs::symlink_metadata(entry.path())?.file_type();
        if !(ft.is_file() || ft.is_dir()) {
            return Err(std::io::Error::new(
                std::io::ErrorKind::InvalidData,
                format!("special file in state tree: {}", entry.path().display()),
            ));
        }
        if ft.is_dir() {
            assert_only_files_and_dirs(&entry.path())?;
        }
    }
    Ok(())
}

Type guard

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

Prevention

When it happens

Trigger: inventory_directory encounters a child whose symlink_metadata shows it is neither a directory nor a regular file (e.g. a Unix fifo, unix socket, or device node) inside the state tree.

Common situations: A database/runtime left a unix socket file in the state directory; a test or dev script created named pipes there; someone mounted a device node into the tree.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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