astrid-runtime/astrid · error
mountpoint is not empty: {}
Error message
mountpoint is not empty: {} What it means
prepare_mountpoint refuses to mount over a non-empty directory. After enforcing permissions it reads the directory and bails if any entry exists, since mounting over populated directories hides their contents and can hide stale data.
Source
Thrown at crates/astrid-storage-provider-fuse/src/mountpoint.rs:55
let metadata = std::fs::symlink_metadata(&requested)?;
if !metadata.is_dir() {
bail!("mountpoint is not a directory: {}", requested.display());
}
let expected_uid = u32::from(getuid());
if metadata.uid() != expected_uid {
bail!(
"mountpoint must be owned by the current OS user: {}",
requested.display()
);
}
let mode = metadata.permissions().mode();
if !existed {
std::fs::set_permissions(&requested, Permissions::from_mode(0o700))?;
} else if mode & 0o077 != 0 {
bail!("mountpoint must be owner-private: {}", requested.display());
}
if std::fs::read_dir(&requested)?.next().is_some() {
bail!("mountpoint is not empty: {}", requested.display());
}
let canonical = requested
.canonicalize()
.with_context(|| format!("canonicalize mountpoint {}", requested.display()))?;
if mountinfo_contains(&canonical)? {
bail!("mountpoint is already mounted: {}", canonical.display());
}
Ok((canonical, !existed))
}
/// Return current owner identity for synthetic inode metadata.
pub(crate) fn owner_ids() -> (u32, u32) {
(getuid().into(), getgid().into())
}
/// Remove a dead FUSE mount if one remains at an exact canonical path.
pub(crate) fn lazy_unmount(mountpoint: &Path) -> Result<()> {
use nix::mount::MntFlags;View on GitHub (pinned to affd8760f4)
Solutions
- Empty the directory (rm -rf <mountpoint>/* including dotfiles) before mounting
- Remove and recreate the directory so the provider creates a fresh private one
- Recover files from a previous failed mount before retrying
- Check for leftover session artifacts (e.g. from rollback cleanup failures)
Example fix
// before ls /mnt/myfuse # stale session files remain // after rm -rf /mnt/myfuse && mkdir -m 700 /mnt/myfuse
Defensive patterns
Strategy: validation
Validate before calling
fn mountpoint_is_empty(path: &std::path::Path) -> std::io::Result<bool> {
Ok(std::fs::read_dir(path)?.next().is_none())
} Try / catch
match prepare_mountpoint(&path) {
Err(e) if e.to_string().contains("not empty") => {
eprintln!("empty {} (check for stale session artifacts) first", path.display());
}
other => other?,
} Prevention
- Use one dedicated empty directory per mount session
- Clean up artifacts after each session, including after crashes
- Never point a FUSE mount at a directory holding user data
- Inspect for lost+found or leftover files when reusing OS-managed directories
When it happens
Trigger: Calling the mount flow with an existing directory that contains files or subdirectories (leftovers from a previous run, user files, or a lost+found).
Common situations: Re-running after a crashed session left artifacts in the mountpoint; pointing the mount at a directory already holding user data; stale files left by a failed rollback.
Understand the failure class
Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.
Related errors
- FUSE mount completed but is absent from the Linux mount tabl
- mountpoint is already registered: {}
- mountpoint ancestor is writable without sticky protection: {
- mountpoint must be absolute
- mountpoint contains traversal: {}
AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09).
Data as JSON: /api/errors/83a5cec8ef90234a.
Report an issue: GitHub.