astrid-runtime/astrid · error

mountpoint parent is not a directory: {}

Error message

mountpoint parent is not a directory: {}

What it means

For directory mountpoints, `prepare_mountpoint` creates the parent directory, verifies it has no filesystem redirects (e.g. OneDrive/cloud placeholder reparse points), and then confirms via `symlink_metadata` that the parent really is a directory. If the parent exists but is a symlink to a file, a regular file, or another non-directory entry, the provider refuses with this error rather than letting WinFsp fail obscurely later.

Source

Thrown at crates/astrid-storage-provider-winfsp/src/main.rs:364

    if is_drive_target(&mountpoint) {
        if std::fs::metadata(&mountpoint).is_ok() {
            bail!(
                "Windows drive target is already in use: {}",
                mountpoint.display()
            );
        }
        return Ok((mountpoint, false));
    }

    let parent = mountpoint
        .parent()
        .context("WinFsp directory mountpoint has no parent")?;
    std::fs::create_dir_all(parent)
        .with_context(|| format!("create mountpoint parent {}", parent.display()))?;
    astrid_core::platform_fs::verify_no_redirects(parent)
        .with_context(|| format!("reject redirected mountpoint parent {}", parent.display()))?;
    if !std::fs::symlink_metadata(parent)?.is_dir() {
        bail!("mountpoint parent is not a directory: {}", parent.display());
    }
    match std::fs::symlink_metadata(&mountpoint) {
        Err(error) if error.kind() == std::io::ErrorKind::NotFound => {},
        Err(error) => {
            return Err(error)
                .with_context(|| format!("inspect mountpoint {}", mountpoint.display()));
        },
        Ok(_) => bail!(
            "WinFsp directory mountpoint must not already exist: {}",
            mountpoint.display()
        ),
    }
    // WinFsp creates and owns directory mountpoint leaves. Treat the leaf as
    // provider-created so failure and unmount cleanup remain idempotent.
    Ok((mountpoint, true))
}

#[cfg(not(windows))]

View on GitHub (pinned to affd8760f4)

Solutions

  1. Inspect the parent path reported in the error and ensure it is a real directory (delete or rename the file/symlink occupying it)
  2. Correct the requested mountpoint path so its parent is a legitimate directory
  3. Re-run `fsutil reparsepoint query` / check attributes if reparse points are involved and remove unexpected ones

Example fix

// before: parent is a file
mount(provider, Some(PathBuf::from("C:\\notes.txt\\storage"))).await?;
// after: parent is a directory
std::fs::create_dir_all("C:\\mounts")?;
mount(provider, Some(PathBuf::from("C:\\mounts\\storage"))).await?;
Defensive patterns

Strategy: validation

Validate before calling

// Verify parent is a real directory before mounting
fn parent_is_dir(mountpoint: &std::path::Path) -> std::io::Result<bool> {
    let parent = mountpoint.parent().ok_or_else(|| std::io::Error::new(std::io::ErrorKind::NotFound, "no parent"))?;
    Ok(parent.symlink_metadata()?.is_dir())
}

Prevention

When it happens

Trigger: Requesting a directory mountpoint whose parent path (after `create_dir_all`) exists but is not a directory — e.g. `C:\data\file.txt\leaf` where `file.txt` is a regular file, or a parent that is a file-type symlink/reparse point surviving the redirect check.

Common situations: Typo in the mount path causing a filename to be used as a directory; a file was created earlier at the intended parent path; junction/symlink structures left over from previous setups.

Related errors


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