astrid-runtime/astrid · error
WinFsp mountpoint is not a directory: {}
Error message
WinFsp mountpoint is not a directory: {} What it means
wait_for_mountpoint_ready polls the mountpoint until std::fs::metadata reports a directory. A directory mount appears as a WinFsp junction; the code follows the reparse point so readiness means the mounted root actually serves I/O. If the path exists but metadata says it is not a directory (typically a regular file), the wait fails immediately with this error.
Source
Thrown at crates/astrid-storage-provider-winfsp/src/win.rs:108
stdout.flush().context("flush WinFsp readiness")?;
let result = runtime.block_on(daemon_loop(filesystem, control_listener));
if let Err(error) = result {
eprintln!("{PROVIDER_NAME}: daemon stopped after failure: {error:#}");
return Err(error);
}
Ok(())
}
fn wait_for_mountpoint_ready(mountpoint: &Path) -> Result<()> {
let started = Instant::now();
loop {
// A directory mount is represented by a WinFsp junction. Follow that
// reparse point so readiness proves the mounted root is serving I/O,
// rather than inspecting the junction object itself.
match std::fs::metadata(mountpoint) {
Ok(metadata) if metadata.is_dir() => return Ok(()),
Ok(_) => bail!(
"WinFsp mountpoint is not a directory: {}",
mountpoint.display()
),
Err(error) if error.kind() == std::io::ErrorKind::NotFound => {},
Err(error) => {
return Err(error).with_context(|| {
format!(
"inspect WinFsp mountpoint readiness {}",
mountpoint.display()
)
});
},
}
if started.elapsed() >= MOUNTPOINT_READY_TIMEOUT {
bail!(
"WinFsp mountpoint did not become ready within {} seconds: {}",
MOUNTPOINT_READY_TIMEOUT.as_secs(),
mountpoint.display()View on GitHub (pinned to affd8760f4)
Solutions
- Delete or rename the file occupying the mountpoint path and create a directory in its place (mkdir)
- Pick a different mountpoint path that does not exist or is a directory
- Before mounting, check fs::metadata and abort early if the path exists but is not a directory
Example fix
// before
std::fs::write("C:\\mounts\\astrid", "")?; // creates a file at the mountpoint
mount(...)?;
// after
if let Ok(md) = std::fs::metadata("C:\\mounts\\astrid") {
assert!(md.is_dir(), "mountpoint must be a directory");
} else {
std::fs::create_dir_all("C:\\mounts\\astrid")?;
}
mount(...)?; Defensive patterns
Strategy: validation
Validate before calling
if let Ok(md) = std::fs::metadata(&mountpoint) {
if !md.is_dir() {
return Err(format!("{} exists and is not a directory; remove it or choose another path", mountpoint.display()));
}
} Type guard
fn is_directory(p: &Path) -> bool {
std::fs::metadata(p).map(|m| m.is_dir()).unwrap_or(false)
} Try / catch
match mount_err {
Err(e) if e.to_string().contains("not a directory") => {
let _ = std::fs::remove_file(&mountpoint);
std::fs::create_dir_all(&mountpoint)?;
retry_mount()?;
}
other => other?,
} Prevention
- mkdir (not touch) the intended mountpoint before mounting
- Use unique mountpoint paths per run to avoid stale-file collisions
- Check path existence/type in mount-preparation code
When it happens
Trigger: A regular file exists at the requested mountpoint path, so when the poll finds Ok(metadata) and metadata.is_dir() is false, it bails with the formatted path.
Common situations: Creating the mountpoint with `touch` or a tool that made a file instead of a directory; a leftover file from a previous run at the same path; a stale junction replaced by a file.
Related errors
- no free Windows drive target is available; specify a directo
- WinFsp daemon lease contains a relative endpoint
- WinFsp mountpoint did not become ready within {} seconds: {}
- WinFsp failed to start mount with status {status:#x}
- WinFsp failed to start private mount: {status:#x}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/5cc6f6fd353f20b9.
Report an issue: GitHub.