sxyazi/yazi · warning · io::Error

Trash not supported

Error message

Trash not supported

What it means

The SFTP backend does not implement move-to-trash: remote filesystems have no trash concept, so `trash()` unconditionally returns ErrorKind::Unsupported. Callers must treat trash as unavailable for remote locations and delete explicitly or skip the operation.

Source

Thrown at yazi-vfs/src/engine/sftp/sftp.rs:193

	}

	async fn symlink<S, F>(&self, original: S, _is_dir: F) -> io::Result<()>
	where
		S: AsStrand,
		F: AsyncFnOnce() -> io::Result<bool>,
	{
		let original = original.as_strand().encoded_bytes();

		Ok(self.op().await?.symlink(original, self.path).await?)
	}

	async fn symlink_metadata(&self) -> io::Result<yazi_fs::cha::Cha> {
		let attrs = self.op().await?.lstat(self.path).await?;
		Ok(Cha::try_from((self.path.file_name().unwrap_or_default(), &attrs))?.0)
	}

	async fn trash(&self) -> io::Result<()> {
		Err(io::Error::new(io::ErrorKind::Unsupported, "Trash not supported"))
	}

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

impl<'a> Sftp<'a> {
	pub(super) async fn op(&self) -> io::Result<deadpool::managed::Object<Conn>> {
		self.pool.get().await.map_err(|e| match e {
			PoolError::Timeout(_) => io::Error::new(io::ErrorKind::TimedOut, e.to_string()),
			PoolError::Backend(e) => e,
			e => io::Error::other(e.to_string()),
		})
	}
}

View on GitHub (pinned to 8ebf930f17)

Solutions

  1. Delete permanently instead: call the remove/delete API rather than trash for SFTP URLs
  2. Gate the operation on URL kind — check the file is local before offering trash
  3. Catch the Unsupported error and surface a 'trash is not supported on remote files' message to the user
  4. Configure the client to disable trash for remote mounts so the unsupported path is never hit

Example fix

-- before
vfs.trash(url) -- Unsupported on SFTP
-- after
if url:kind() == 'sftp' then
  vfs.remove(url)
else
  vfs.trash(url)
end
Defensive patterns

Strategy: fallback

Validate before calling

local supported = url:kind() == 'local' or url:kind() == 'archive' -- trash only makes sense locally
if not supported then return vfs.remove(url) end

Type guard

fn is_local(url: &Url) -> bool { matches!(url, Url::Local { .. }) }

Try / catch

match file.trash().await {
    Err(e) if e.kind() == io::ErrorKind::Unsupported => {
        // remote: fall back to permanent delete
        file.remove().await
    }
    r => r,
}

Prevention

When it happens

Trigger: Any delete-with-trash request on an SFTP-backed file/folder — e.g. the file manager's delete command (with trash enabled) targeting a remote entry.

Common situations: Users pressing the trash/delete keybinding on files in an SSH mount; sync tools replicating local trash semantics to remote paths.

Related errors


AI-assisted analysis of sxyazi/yazi@8ebf930f17 (2026-09-02). Data as JSON: /api/errors/447a26592e7eb30b. Report an issue: GitHub.