{"record":{"id":"7c61b05ec4c865fc","repo":"astrid-runtime/astrid","slug":"cannot-unmount-a-relative-mountpoint","errorCode":null,"errorMessage":"cannot unmount a relative mountpoint","messagePattern":"cannot unmount a relative mountpoint","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-provider-fuse/src/mountpoint.rs","lineNumber":76,"sourceCode":"        .canonicalize()\n        .with_context(|| format!(\"canonicalize mountpoint {}\", requested.display()))?;\n    if mountinfo_contains(&canonical)? {\n        bail!(\"mountpoint is already mounted: {}\", canonical.display());\n    }\n    Ok((canonical, !existed))\n}\n\n/// Return current owner identity for synthetic inode metadata.\npub(crate) fn owner_ids() -> (u32, u32) {\n    (getuid().into(), getgid().into())\n}\n\n/// Remove a dead FUSE mount if one remains at an exact canonical path.\npub(crate) fn lazy_unmount(mountpoint: &Path) -> Result<()> {\n    use nix::mount::MntFlags;\n\n    if !mountpoint.is_absolute() {\n        bail!(\"cannot unmount a relative mountpoint\");\n    }\n    match nix::mount::umount2(mountpoint, MntFlags::MNT_DETACH) {\n        Ok(()) | Err(nix::errno::Errno::EINVAL) => Ok(()),\n        Err(error) => Err(anyhow::anyhow!(\n            \"lazy unmount {}: {error}\",\n            mountpoint.display()\n        )),\n    }\n}\n\n/// Whether `/proc/self/mountinfo` has a mount at this exact path.\npub(crate) fn mountinfo_contains(mountpoint: &Path) -> Result<bool> {\n    let expected = mountpoint\n        .to_str()\n        .context(\"mountpoint must be canonical Unicode text\")?\n        .as_bytes();\n    let mounts = std::fs::read(\"/proc/self/mountinfo\").context(\"read Linux mount table\")?;\n    Ok(mounts","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-provider-fuse/src/mountpoint.rs#L58-L94","documentation":"lazy_unmount only performs a lazy detach (umount2 with MNT_DETACH) on absolute paths; a relative path could resolve to a different location depending on cwd, so it is rejected up front. This keeps the unmount target unambiguous.","triggerScenarios":"Calling lazy_unmount with a relative Path (e.g. \"my-mount\" or \"./mount\") instead of an absolute path; passing a mountpoint string that was never canonicalized.","commonSituations":"Storing the user-supplied mountpoint string in config instead of the canonical path returned by prepare_mountpoint; reconstructing the path relative to a working directory.","solutions":["Canonicalize the path before unmounting (std::fs::canonicalize or store the canonical path from prepare_mountpoint)","Ensure the path is absolute (starts with /) before calling lazy_unmount","Persist the canonical mountpoint returned by the mount flow, not the user input"],"exampleFix":"// before\nlazy_unmount(Path::new(\"./mount\"))?\n// after\nlet canonical = std::fs::canonicalize(\"./mount\")?;\nlazy_unmount(&canonical)?","handlingStrategy":"validation","validationCode":"fn ensure_absolute(path: &std::path::Path) -> Option<&std::path::Path> {\n    path.is_absolute().then_some(path)\n}","typeGuard":"fn is_absolute_path(path: &std::path::Path) -> bool {\n    path.is_absolute()\n}","tryCatchPattern":"match lazy_unmount(path) {\n    Err(e) if e.to_string().contains(\"relative mountpoint\") => {\n        let canonical = std::fs::canonicalize(path)?;\n        lazy_unmount(&canonical)?\n    }\n    other => other?,\n}","preventionTips":["Store the canonical path returned by prepare_mountpoint for later unmounts","Call std::fs::canonicalize before unmounting user-supplied paths","Never persist relative paths in session/registry state","Assert path.is_absolute() at configuration load time"],"tags":["fuse","mount","path"],"backgroundTag":"invalid-argument-value","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}