sxyazi/yazi · error

trash item outside of trash folders

Error message

trash item outside of trash folders

What it means

The freedesktop Trash::entry resolves a trash id by parsing its top-level .trashinfo and then verifying that the trash root recorded in the info belongs to a known trash folder (via os_limited::trash_folders()). If the info's root is not among the registered trash folders, it returns NotFound "trash item outside of trash folders". This prevents operating on trashinfo files found outside managed trash locations (e.g. arbitrary paths passed as ids).

Solutions

  1. Ensure the drive/mount containing the .Trash-<uid> folder is mounted before accessing the trashed item.
  2. Re-derive ids from the current trash listing (tops()/list()) instead of reusing persisted ids across mounts or config changes.
  3. Check XDG_DATA_HOME / trash folder configuration so the folder that holds the item is registered as a trash folder.
  4. Treat io::ErrorKind::NotFound as 'item no longer available' and refresh the trash view.
Defensive patterns

Strategy: try-catch

Try / catch

match trash.entry(&id).await {
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => refresh_trash_view(), // item's trash folder is gone/unmounted
    other => other?,
}

Prevention

When it happens

Trigger: Building a trash id from a .trashinfo path located outside recognized trash folders (home Trash, top-level .Trash-<uid> dirs), then calling entry(); stale ids whose trash folder was moved, renamed, or mounted differently; a custom TRASH folder env/config change.

Common situations: External drives whose .Trash-1000 directory is no longer mounted; XDG_DATA_HOME changed since the id was created; ids persisted across sessions and the trash folder set changed.

Related errors


AI-assisted analysis of sxyazi/yazi@a541adde4e (2026-09-02). Data as JSON: /api/errors/3b5af4e132fe37a9. Report an issue: GitHub.

Appendix: source

Thrown at yazi-fs/src/trash/freedesktop/trash.rs:39

			return Err(io::Error::new(io::ErrorKind::InvalidInput, "trash item is not a directory"));
		}

		fs::read_dir(&entry.backing)?
			.map(|dent| {
				let dent = dent?;
				entry.child(dent.file_name())
			})
			.collect()
	}

	pub(crate) fn entry(&self, id: &TrashId) -> io::Result<TrashEntry> {
		let info = TrashInfo::parse(id.top())?;
		if !os_limited::trash_folders()
			.map_err(io::Error::other)?
			.iter()
			.any(|folder| folder == &info.root)
		{
			return Err(io::Error::new(io::ErrorKind::NotFound, "trash item outside of trash folders"));
		}

		if id.has_rel() && !fs::symlink_metadata(&info.backing)?.file_type().is_dir() {
			return Err(io::Error::new(io::ErrorKind::InvalidInput, "trash item is not a directory"));
		}

		let (backing, original) = if id.has_rel() {
			(info.backing.join(id.rel()), info.original.join(id.rel()))
		} else {
			(info.backing, info.original)
		};
		TrashEntry::new(id.clone(), backing, Some(original))
	}

	pub(crate) fn metadata(&self, entry: &TrashEntry, follow: bool) -> io::Result<Cha> {
		Ok(if follow { entry.cha } else { entry.lcha })
	}

View on GitHub (pinned to a541adde4e)