sxyazi/yazi · error · io::Error

invalid trash entry path

Error message

invalid trash entry path

What it means

Returned by TrashId::new when rel is relative but contains parent components ('..'), which would let an id escape its trashed top-level item. This is an anti-traversal invariant enforced at id-construction time with io::ErrorKind::InvalidInput.

Source

Thrown at yazi-fs/src/trash/trash_id.rs:26

pub(crate) struct TrashId {
	top: PathBuf,
	rel: PathBuf,
}

impl TrashId {
	pub(super) fn new<T, R>(top: T, rel: R) -> io::Result<Self>
	where
		T: Into<PathBuf>,
		R: Into<PathBuf>,
	{
		let top = top.into();
		let rel = rel.into();

		if top.as_os_str().is_empty() || !rel.is_relative() {
			return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid trash entry"));
		}
		if rel.has_parent_component() {
			return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid trash entry path"));
		}

		Ok(Self { top, rel })
	}

	pub(super) fn top(&self) -> &Path { &self.top }

	pub(super) fn rel(&self) -> &Path { &self.rel }

	#[cfg(target_os = "macos")]
	pub(super) fn path(&self) -> PathBuf {
		if self.has_rel() { self.top.join(&self.rel) } else { self.top.clone() }
	}

	pub(super) fn child(&self, name: &OsStr) -> io::Result<Self> {
		let rel = self.rel.join(name);
		if !rel.is_relative() || rel.has_parent_component() {
			return Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid trash entry path"));

View on GitHub (pinned to 94abcfa92f)

Solutions

  1. Reject or sanitize rel components equal to '..' before constructing the id.
  2. Use only names returned by Trash:list (real file names cannot be '..').
  3. Keep rel built exclusively by joining entry.child() results.

Example fix

-- Lua: before
local rel = user_input -- could be "../.."
local e = ya.fs("trash"):entry({ top = top, rel = rel })
-- after
local rel = user_input:gsub("[^/]+", function(s) return s == ".." and "" or s end):gsub("/+", "/")
local e = ya.fs("trash"):entry({ top = top, rel = rel })
Defensive patterns

Strategy: validation

Validate before calling

-- Lua: strip parent components from rel
local function sanitize_rel(rel)
  local parts = {}
  for seg in rel:gmatch("[^/]+") do
    if seg ~= ".." and seg ~= "." then table.insert(parts, seg) end
  end
  return table.concat(parts, "/")
end

Type guard

local function is_safe_rel(rel)
  for seg in rel:gmatch("[^/]+") do if seg == ".." then return false end end
  return rel:sub(1, 1) ~= "/"
end

Try / catch

if not is_safe_rel(id.rel) then id.rel = sanitize_rel(id.rel) end
local e = ya.fs("trash"):entry(id)

Prevention

When it happens

Trigger: rel = '../evil', rel = 'a/../../b', or any segment equal to '..' in the Lua table passed to Trash:entry.

Common situations: Plugins building rel by joining untrusted name strings; path normalization logic that leaves '..' segments; user input pasted into a trash navigation command.

Related errors


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