astrid-runtime/astrid · error

private path has no parent

Error message

private path has no parent: {}

What it means

While verifying that a private path is not redirected, verify_no_redirects_unix needs the parent directory to open it no-follow. If path.parent() returns None (a bare root or malformed path), it fails with io::ErrorKind::InvalidInput.

Solutions

  1. Pass a concrete nested path (e.g. $HOME/.astrid) rather than a filesystem root.
  2. Validate the configured path has a parent before calling: path.parent().is_some().
  3. Fix path construction so it never degenerates to the root or empty path.

Example fix

// before
let target: &Path = cfg.private_dir.as_ref();
verify_no_redirects(target)?;
// after
let target: &Path = cfg.private_dir.as_ref();
assert!(target.parent().is_some(), "private path must not be a filesystem root");
verify_no_redirects(target)?;
Defensive patterns

Strategy: validation

Validate before calling

if path.parent().is_none() {
    return Err("private path must not be a filesystem root".into());
}

Type guard

fn has_parent(p: &std::path::Path) -> bool { p.parent().is_some() }

Try / catch

match verify_no_redirects(&path) {
    Err(e) if e.kind() == io::ErrorKind::InvalidInput => eprintln!("path must be nested, not a root: {e}"),
    other => other?,
}

Prevention

When it happens

Trigger: Calling verify_no_redirects with a path such as "/" or an empty/oddly formed Path whose parent cannot be determined.

Common situations: Misconfigured root path in config (e.g. private dir set to "/"); programmatic path built by repeatedly calling .parent() until None; a bug constructing paths from empty strings.

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

Appendix: source

Thrown at crates/astrid-core/src/platform_fs.rs:432

        let _ = path;
        Ok(())
    }
}

#[cfg(unix)]
fn verify_no_redirects_unix(path: &Path) -> io::Result<()> {
    use nix::fcntl::{OFlag, openat};
    use nix::sys::stat::Mode;

    match std::fs::symlink_metadata(path) {
        Ok(metadata) if metadata.file_type().is_symlink() => Err(io::Error::new(
            io::ErrorKind::InvalidData,
            format!("private path is redirected: {}", path.display()),
        )),
        Ok(metadata) if metadata.is_dir() => open_directory_no_follow_unix(path).map(drop),
        Ok(_) => {
            let parent = path.parent().ok_or_else(|| {
                io::Error::new(
                    io::ErrorKind::InvalidInput,
                    format!("private path has no parent: {}", path.display()),
                )
            })?;
            let name = path.file_name().ok_or_else(|| {
                io::Error::new(
                    io::ErrorKind::InvalidInput,
                    format!("private path has no file name: {}", path.display()),
                )
            })?;
            let directory = open_directory_no_follow_unix(parent)?;
            let flags = OFlag::O_RDONLY | OFlag::O_NOFOLLOW | OFlag::O_CLOEXEC | OFlag::O_NONBLOCK;
            openat(&directory, name, flags, Mode::empty())
                .map(std::fs::File::from)
                .map(drop)
                .map_err(nix_io_error)
        },
        Err(error) if error.kind() == io::ErrorKind::NotFound => {

View on GitHub (pinned to affd8760f4)