{"record":{"id":"1fe91a184da44723","repo":"sxyazi/yazi","slug":"trash-item-has-no-put-back-location","errorCode":null,"errorMessage":"trash item has no put-back location","messagePattern":"trash item has no put-back location","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"yazi-fs/src/trash/freedesktop/trash.rs","lineNumber":112,"sourceCode":"\t\tfs::remove_file(&entry.backing)?;\n\t\tif !entry.has_rel() {\n\t\t\tfs::remove_file(entry.top())?;\n\t\t}\n\t\tOk(())\n\t}\n\n\tpub(crate) fn remove_dir(&self, entry: &TrashEntry) -> io::Result<()> {\n\t\tfs::remove_dir(&entry.backing)?;\n\t\tif !entry.has_rel() {\n\t\t\tfs::remove_file(entry.top())?;\n\t\t}\n\t\tOk(())\n\t}\n\n\tpub(crate) fn restore(&self, entries: TrashEntries) -> io::Result<()> {\n\t\tfor entry in entries {\n\t\t\tlet to = entry.original.clone().ok_or_else(|| {\n\t\t\t\tio::Error::new(io::ErrorKind::NotFound, \"trash item has no put-back location\")\n\t\t\t})?;\n\n\t\t\trestore_item(&entry.backing, &to)?;\n\n\t\t\tif !entry.has_rel() {\n\t\t\t\tfs::remove_file(entry.top())?;\n\t\t\t}\n\t\t}\n\t\tOk(())\n\t}\n\n\t// FIXME: also rename or remove the .trashinfo file in the info folder\n\tpub(crate) fn rename(&self, entry: &TrashEntry, path: &Path) -> io::Result<()> {\n\t\tfs::rename(&entry.backing, path)\n\t}\n\n\tpub(crate) fn empty(&self) -> io::Result<()> {\n\t\tfor entry in self.tops()? {","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/sxyazi/yazi/blob/94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2/yazi-fs/src/trash/freedesktop/trash.rs#L94-L130","documentation":"`Trash::restore` (freedesktop/trash.rs:112) iterates entries and requires each to carry an `original` put-back path; an entry without one yields `ErrorKind::NotFound`, `trash item has no put-back location`. In the freedesktop flow `original` comes from the `Path=` line of the `.trashinfo`, so this fires for entries constructed without that metadata (e.g. entries built from bare `TrashId`s rather than `Trash::entry`).","triggerScenarios":"Restoring a `TrashEntries` collection that includes entries created via `TrashEntry::new/top` with `original: None`, or ids for `.trashinfo` files whose `Path=` could not be honored.","commonSituations":"Plugins/Lua building restore batches from ids alone; trash metadata partially damaged while the backing file still exists.","solutions":["Build restore batches only from entries obtained via `Trash::entry(id)`/`Trash::list`, which carry the parsed original path.","For items already lacking put-back info, restore manually: move the file out of `<root>/files/` to the desired location and delete the orphaned `.trashinfo`.","Filter out `original.is_none()` entries before calling restore so one bad item does not abort the batch."],"exampleFix":"// before\ntrash::restore(all_entries)?; // aborts on first entry with original == None\n\n// after\nlet restorable: Vec<_> = all_entries.into_iter().filter(|e| e.original.is_some()).collect();\ntrash::restore(restorable)?;\n// report skipped items to the user for manual restore","handlingStrategy":"fallback","validationCode":"let restorable: Vec<_> = entries.into_iter().filter(|e| e.original.is_some()).collect();\nlet skipped = total - restorable.len(); // report for manual restore","typeGuard":"fn is_restorable(entry: &TrashEntry) -> bool {\n    entry.original.is_some()\n}","tryCatchPattern":"match trash::restore(entries) {\n    Ok(()) => {}\n    Err(e) if e.kind() == io::ErrorKind::NotFound => {\n        // filter out entries with original == None, retry the rest,\n        // then manually move the leftovers out of <root>/files/\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Build restore batches exclusively from `Trash::entry`/`list` results, which carry the parsed original path.","Filter `original.is_none()` entries before restoring so one bad item does not abort the batch.","Know the manual escape hatch: move files out of ~/.local/share/Trash/files/ and delete the matching .trashinfo."],"tags":["trash","restore","put-back","not-found"],"backgroundTag":null,"analyzedSha":"94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2","analyzedAt":"2026-08-16T09:56:24.836Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}