sxyazi/yazi · error · io::Error

Unsupported OS for trash operation

Error message

Unsupported OS for trash operation

What it means

`Local::trash()` (local.rs:222) moves a path to the OS trash via the `trash` crate. On `target_os = "android"` the operation is unconditionally rejected with `ErrorKind::Unsupported`, because Android has no freedesktop/macOS trash protocol the crate can use. macOS and other Unix/Windows targets take the `trash::delete` paths.

Source

Thrown at yazi-fs/src/engine/local/local.rs:222

		{
			tokio::fs::symlink_file(original, self.path).await
		}
	}

	#[inline]
	async fn symlink_metadata(&self) -> io::Result<Cha> {
		Ok(Cha::new(
			self.path.file_name().unwrap_or_default(),
			tokio::fs::symlink_metadata(self.path).await?,
		))
	}

	async fn trash(&self) -> io::Result<()> {
		let path = self.path.to_owned();
		tokio::task::spawn_blocking(move || {
			#[cfg(target_os = "android")]
			{
				Err(io::Error::new(io::ErrorKind::Unsupported, "Unsupported OS for trash operation"))
			}
			#[cfg(target_os = "macos")]
			{
				use trash::{TrashContext, macos::{DeleteMethod, TrashContextExtMacos}};
				let mut ctx = TrashContext::default();
				ctx.set_delete_method(DeleteMethod::NsFileManager);
				ctx.delete(path).map_err(io::Error::other)
			}
			#[cfg(all(not(target_os = "macos"), not(target_os = "android")))]
			{
				trash::delete(path).map_err(io::Error::other)
			}
		})
		.await?
	}

	#[inline]
	fn url(&self) -> Url<'_> { self.url }

View on GitHub (pinned to 94abcfa92f)

Solutions

  1. On Android, offer permanent delete instead of trash (bind the remove/delete-without-trash action).
  2. Gate trash UI/actions with `#[cfg(not(target_os = "android"))]` or a runtime capability check so the action is not offered.
  3. If trash semantics are required on Android, implement an app-private trash folder yourself and route deletes there.

Example fix

// before
local.trash().await?; // Err(Unsupported) on Android

// after
#[cfg(target_os = "android")]
local.remove().await?; // permanent delete on Android
#[cfg(not(target_os = "android"))]
local.trash().await?;
Defensive patterns

Strategy: fallback

Validate before calling

#[cfg(target_os = "android")]
fn trash_supported() -> bool { false }
#[cfg(not(target_os = "android"))]
fn trash_supported() -> bool { true }

Try / catch

match local.trash().await {
    Ok(()) => {}
    Err(e) if e.kind() == io::ErrorKind::Unsupported => {
        // Android: fall back to permanent removal after user confirmation
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Building yazi for Android (`aarch64-linux-android` target) and invoking any delete-to-trash action (default `d` keybinding or the trash plugin API) on any file.

Common situations: Running a Termux/build of yazi on Android; CI cross-compilation tests that execute trash code paths on an Android target.

Related errors


AI-assisted analysis of sxyazi/yazi@94abcfa92f (2026-08-16). Data as JSON: /api/errors/6f8b213f00793898. Report an issue: GitHub.