sxyazi/yazi · error · io::Error
trash item has no put-back location
Error message
trash item has no put-back location
What it means
`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`).
Source
Thrown at yazi-fs/src/trash/freedesktop/trash.rs:112
fs::remove_file(&entry.backing)?;
if !entry.has_rel() {
fs::remove_file(entry.top())?;
}
Ok(())
}
pub(crate) fn remove_dir(&self, entry: &TrashEntry) -> io::Result<()> {
fs::remove_dir(&entry.backing)?;
if !entry.has_rel() {
fs::remove_file(entry.top())?;
}
Ok(())
}
pub(crate) fn restore(&self, entries: TrashEntries) -> io::Result<()> {
for entry in entries {
let to = entry.original.clone().ok_or_else(|| {
io::Error::new(io::ErrorKind::NotFound, "trash item has no put-back location")
})?;
restore_item(&entry.backing, &to)?;
if !entry.has_rel() {
fs::remove_file(entry.top())?;
}
}
Ok(())
}
// FIXME: also rename or remove the .trashinfo file in the info folder
pub(crate) fn rename(&self, entry: &TrashEntry, path: &Path) -> io::Result<()> {
fs::rename(&entry.backing, path)
}
pub(crate) fn empty(&self) -> io::Result<()> {
for entry in self.tops()? {View on GitHub (pinned to 94abcfa92f)
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.
Example fix
// before trash::restore(all_entries)?; // aborts on first entry with original == None // after let restorable: Vec<_> = all_entries.into_iter().filter(|e| e.original.is_some()).collect(); trash::restore(restorable)?; // report skipped items to the user for manual restore
Defensive patterns
Strategy: fallback
Validate before calling
let restorable: Vec<_> = entries.into_iter().filter(|e| e.original.is_some()).collect(); let skipped = total - restorable.len(); // report for manual restore
Type guard
fn is_restorable(entry: &TrashEntry) -> bool {
entry.original.is_some()
} Try / catch
match trash::restore(entries) {
Ok(()) => {}
Err(e) if e.kind() == io::ErrorKind::NotFound => {
// filter out entries with original == None, retry the rest,
// then manually move the leftovers out of <root>/files/
}
Err(e) => return Err(e),
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Plugins/Lua building restore batches from ids alone; trash metadata partially damaged while the backing file still exists.
Related errors
- trash item has no put-back location
- restore target already exists: {to:?}
- trash item outside of trash folders
- trash item has no put-back location
- trash item has no put-back name
AI-assisted analysis of sxyazi/yazi@94abcfa92f (2026-08-16).
Data as JSON: /api/errors/1fe91a184da44723.
Report an issue: GitHub.