{"record":{"id":"e59b0a9a115246a2","repo":"astrid-runtime/astrid","slug":"macos-unmount-failed-with-status","errorCode":null,"errorMessage":"macOS unmount failed with {status}","messagePattern":"macOS unmount failed with (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/astrid-storage-provider-fskit/src/main.rs","lineNumber":582,"sourceCode":"pub(crate) fn native_mount(\n    lease: &StorageMountLeaseV1,\n    mountpoint: &Path,\n) -> std::future::Ready<Result<()>> {\n    let _ = (lease, mountpoint);\n    std::future::ready(Err(anyhow::anyhow!(\n        \"the FSKit provider is available only on macOS\"\n    )))\n}\n\n#[cfg(target_os = \"macos\")]\npub(crate) async fn native_unmount(mountpoint: &Path) -> Result<()> {\n    let status = tokio::process::Command::new(\"/sbin/umount\")\n        .arg(mountpoint)\n        .status()\n        .await\n        .context(\"invoke macOS unmount\")?;\n    if !status.success() {\n        bail!(\"macOS unmount failed with {status}\");\n    }\n    Ok(())\n}\n\n#[cfg(target_os = \"macos\")]\nfn native_mount_is_active(mountpoint: &Path) -> Result<bool> {\n    let status = nix::sys::statfs::statfs(mountpoint)\n        .with_context(|| format!(\"inspect native mountpoint {}\", mountpoint.display()))?;\n    Ok(status.filesystem_type_name() == \"astridfs\")\n}\n\n#[cfg(not(target_os = \"macos\"))]\npub(crate) fn native_unmount(mountpoint: &Path) -> std::future::Ready<Result<()>> {\n    let _ = mountpoint;\n    std::future::ready(Err(anyhow::anyhow!(\n        \"the FSKit provider is available only on macOS\"\n    )))\n}","sourceCodeStart":564,"sourceCodeEnd":600,"githubUrl":"https://github.com/astrid-runtime/astrid/blob/affd8760f44190dbdfbec23403f4c4b642c33112/crates/astrid-storage-provider-fskit/src/main.rs#L564-L600","documentation":"native_unmount runs /sbin/umount <mountpoint> and bails if the process reports failure, including the exit status in the message. A non-zero status means the kernel refused to unmount — the message shows the raw status (e.g. exit code 1/16) rather than a classified cause.","triggerScenarios":"Calling unmount (or rollback_after_native_failure, actual_fskit_mount_and_unmount_round_trip) on macOS when umount fails: files open on the volume, a process with cwd inside the mountpoint, or the mount no longer exists.","commonSituations":"Finder or a terminal holding the volume open; an editor or build daemon with cwd under the mountpoint; trying to unmount an already-unmounted path (stale registry record).","solutions":["Find and close processes using the volume: lsof +D <mountpoint> or sudo umount -f <mountpoint> if safe","Check whether the path is actually still mounted before unmounting (native_mount_is_active)","Retry after closing apps (Finder windows, terminals) that reference the volume","If the registry record is stale, remove/reconcile the record and unmount manually"],"exampleFix":"// before\nunmount(&selector).await?; // \"macOS unmount failed with exit status: 1\"\n// after\nif native_mount_is_active(&mountpoint)? {\n    close_open_handles(&mountpoint);\n    unmount(&selector).await?;\n}","handlingStrategy":"try-catch","validationCode":"let active = native_mount_is_active(&mountpoint)?;\nif !active { /* nothing to unmount; skip or reconcile record */ }","typeGuard":null,"tryCatchPattern":"match unmount(&selector).await {\n    Err(e) if e.to_string().contains(\"macOS unmount failed\") => {\n        // find blockers\n        // lsof +D <mountpoint>; close Finder/terminal handles; retry once\n    }\n    r => r?,\n}","preventionTips":["Close open files and shells with cwd under the mountpoint before unmounting","Check mount activity before attempting unmount to avoid stale records","Use `mount | grep` to confirm state on macOS","Implement a retry with backoff for transient EBUSY"],"tags":["macos","unmount","subprocess","filesystem"],"backgroundTag":"command-failed","analyzedSha":"affd8760f44190dbdfbec23403f4c4b642c33112","analyzedAt":"2026-09-09T21:28:12.402Z","contentChangedAt":"2026-09-09T21:28:12.402Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}