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

Astrid home without a layout sentinel is redirected or not a

Error message

Astrid home without a layout sentinel is redirected or not a directory: {}

What it means

Thrown by AstridDirs::ensure when the home root has no layout sentinel, and the root itself is either a symlink or not a directory. This guards against redirected or malformed roots being silently initialized as an Astrid home.

Source

Thrown at crates/astrid-core/src/dirs.rs:352

    /// # Errors
    ///
    /// Returns an error if directory creation or permission setting fails.
    pub fn ensure(&self) -> io::Result<()> {
        self.validate_run_dir()?;
        let existing_layout = self.layout_version()?;
        if let Some(version) = existing_layout.as_deref()
            && version != LEGACY_LAYOUT_VERSION
            && version != LAYOUT_VERSION
        {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!("unsupported Astrid home layout version {version:?}"),
            ));
        }
        if existing_layout.is_none() {
            match std::fs::symlink_metadata(self.root()) {
                Ok(metadata) if metadata.file_type().is_symlink() || !metadata.is_dir() => {
                    return Err(io::Error::new(
                        io::ErrorKind::InvalidData,
                        format!(
                            "Astrid home without a layout sentinel is redirected or not a directory: {}",
                            self.root().display()
                        ),
                    ));
                },
                Ok(_) => {},
                Err(error) if error.kind() == io::ErrorKind::NotFound => {},
                Err(error) => return Err(error),
            }
        }
        let mut dirs = Vec::<PathBuf>::new();
        if existing_layout.as_deref() == Some(LEGACY_LAYOUT_VERSION) {
            dirs.extend([
                self.etc_dir(),
                self.hooks_dir(),
                self.var_dir(),

View on GitHub (pinned to affd8760f4)

Solutions

  1. Replace the symlink/file at the home path with a real directory and re-run ensure
  2. Remove the stale non-directory entry and re-initialize the home
  3. If redirection is intended, point ASTRID_HOME directly at the target directory

Example fix

// before: root is a symlink
ln -s /mnt/volume/.astrid ~/.astrid
// after: use the target path directly
export ASTRID_HOME=/mnt/volume/.astrid
Defensive patterns

Strategy: validation

Validate before calling

let md = std::fs::symlink_metadata(&home_path)?;
assert!(md.is_dir() && !md.file_type().is_symlink(), "home must be a real directory");

Type guard

fn is_real_dir(p: &std::path::Path) -> bool {
    std::fs::symlink_metadata(p).map(|m| m.is_dir() && !m.file_type().is_symlink()).unwrap_or(false)
}

Try / catch

match dirs.ensure() {
    Err(e) if e.to_string().contains("redirected or not a directory") => {
        eprintln!("Home path is a symlink or non-directory; fix the path");
    },
    other => other?,
}

Prevention

When it happens

Trigger: Calling ensure on a path where the root is a symlink (e.g. redirecting the home elsewhere) or a regular file/socket, with no layout sentinel present.

Common situations: Users symlinking their Astrid home to another volume, a stale file occupying the expected home path, or a partially deleted home directory.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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