{"record":{"id":"44a2aeee7aa5aa8e","repo":"spacedriveapp/spacedrive","slug":"failed-to-move-to-trash","errorCode":null,"errorMessage":"Failed to move to trash: {}","messagePattern":"Failed to move to trash: (.+?)","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"core/src/ops/files/delete/strategy.rs","lineNumber":227,"sourceCode":"\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tOk(total)\n\t}\n\n\t/// Move file to the system trash/recycle bin.\n\t///\n\t/// Uses the `trash` crate for native platform support:\n\t/// - Windows: SHFileOperation → Recycle Bin\n\t/// - macOS: NSFileManager → Trash\n\t/// - Linux: XDG trash spec\n\t#[cfg(any(target_os = \"windows\", target_os = \"macos\", target_os = \"linux\"))]\n\tpub async fn move_to_trash(&self, path: &Path) -> Result<(), std::io::Error> {\n\t\tlet path = path.to_path_buf();\n\t\ttokio::task::spawn_blocking(move || {\n\t\t\ttrash::delete(&path).map_err(|e| {\n\t\t\t\tstd::io::Error::new(\n\t\t\t\t\tstd::io::ErrorKind::Other,\n\t\t\t\t\tformat!(\"Failed to move to trash: {}\", e),\n\t\t\t\t)\n\t\t\t})\n\t\t})\n\t\t.await\n\t\t.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e.to_string()))??;\n\n\t\tOk(())\n\t}\n\n\t#[cfg(not(any(target_os = \"windows\", target_os = \"macos\", target_os = \"linux\")))]\n\tpub async fn move_to_trash(&self, _path: &Path) -> Result<(), std::io::Error> {\n\t\tErr(std::io::Error::new(\n\t\t\tstd::io::ErrorKind::Unsupported,\n\t\t\t\"move to trash is not supported on this platform\",\n\t\t))\n\t}","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/spacedriveapp/spacedrive/blob/6dfeccf2113039e35f2ce735f945e70dc3e4ea45/core/src/ops/files/delete/strategy.rs#L209-L245","documentation":"move_to_trash runs trash::delete on a blocking thread and wraps any error into io::Error with ErrorKind::Other; a JoinError from spawn_blocking is wrapped the same way. The trash crate uses NSFileManager on macOS, SHFileOperation on Windows, and the XDG trash spec on Linux, so the concrete failure causes are platform-specific.","triggerScenarios":"Path no longer exists when trash::delete runs (deleted by another process first); headless Linux without an XDG trash implementation (no trash service or ~/.local/share/Trash infra); file on a mount the trash spec cannot handle (some network mounts, tmpfs); permission denied on the file or parent; path with characters the platform API rejects.","commonSituations":"Daemon running in a container or headless server where XDG trash directories do not exist; trashing from external or network volumes; racing with sync software that removes the file first.","solutions":["Check the file exists immediately before trashing; if the target is gone, treat as already-deleted success","On headless Linux, set XDG_DATA_HOME and ensure the trash directories exist, or offer permanent delete as the fallback path","Verify the daemon user can move the file into the trash directory (permissions on file, parent, and trash dir)","Confirm the platform is windows/macos/linux: the cfg gate compiles this helper out elsewhere, so a wrong-platform build fails at link/compile instead"],"exampleFix":"// before: trash failure aborts the delete flow\nstrategy.move_to_trash(&path).await?;\n\n// after: fall back to permanent delete when trash is unavailable (e.g. headless Linux)\nif strategy.move_to_trash(&path).await.is_err() {\n    tracing::warn!(?path, \"Trash failed; falling back to permanent delete\");\n    strategy.permanent_delete(&path).await?;\n}","handlingStrategy":"fallback","validationCode":"// Before trashing, confirm the path still exists\nmatch tokio::fs::symlink_metadata(path).await {\n    Ok(_) => { /* proceed */ }\n    Err(e) if e.kind() == std::io::ErrorKind::NotFound => return Ok(()), // already gone\n    Err(e) => return Err(e),\n}","typeGuard":null,"tryCatchPattern":"match strategy.move_to_trash(path).await {\n    Err(e) => {\n        tracing::warn!(?path, error = %e, \"trash unavailable; falling back to permanent delete\");\n        strategy.permanent_delete(path).await // or surface a user choice\n    }\n    ok => ok,\n}","preventionTips":["On headless Linux, ensure XDG_DATA_HOME and trash dirs exist, or default to permanent delete","Always offer a permanent-delete fallback for volumes without trash support","Check existence right before deletion to avoid races with sync software"],"tags":["trash","filesystem","deletion","platform-specific"],"backgroundTag":null,"analyzedSha":"6dfeccf2113039e35f2ce735f945e70dc3e4ea45","analyzedAt":"2026-08-16T11:26:17.074Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}