sxyazi/yazi · error · io::Error

invalid original trash path

Error message

invalid original trash path

What it means

After parsing the `Path=` value, `TrashInfo::parse` (trash_info.rs:36) sanity-checks the resulting original path: it must have a file name. Paths like `/`, `..`, or anything ending in a parent component have no terminal file name and are rejected with `ErrorKind::InvalidData`, `invalid original trash path`, because no file could ever be restored there.

Source

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

		if info.extension() != Some(OsStr::new("trashinfo")) {
			return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid trash info path"));
		}

		// /home/alice/.local/share/Trash
		let root = info
			.parent()
			.filter(|p| p.file_name() == Some(OsStr::new("info")))
			.and_then(Path::parent)
			.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "invalid trash info path"))?;

		// cat.jpg
		let stem = info
			.file_stem()
			.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, "invalid trash info path"))?;

		let original = Self::parse_original(info, root)?;
		if original.file_name().is_none() {
			return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid original trash path"));
		}

		Ok(Self { root: root.to_owned(), backing: root.join("files").join(stem), original })
	}

	fn parse_original(info: &Path, root: &Path) -> io::Result<PathBuf> {
		let mut reader = BufReader::new(File::open(info)?);
		let mut line = Vec::new();

		reader.read_until(b'\n', &mut line)?;
		Self::trim_line(&mut line);
		if line != b"[Trash Info]" {
			return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid trash info header"));
		}

		loop {
			line.clear();
			if reader.read_until(b'\n', &mut line)? == 0 {

View on GitHub (pinned to 94abcfa92f)

Solutions

  1. Edit the `.trashinfo` and set `Path=` to the real absolute original location (e.g. `Path=/home/alice/report.pdf`).
  2. Delete the broken `.trashinfo` (and its orphaned backing file in `files/`) if the original location is unknown.
  3. If you generate trash metadata, always write absolute paths with a final component.

Example fix

# before (~/.local/share/Trash/info/x.trashinfo)
[Trash Info]
Path=/

# after
[Trash Info]
Path=/home/alice/report.pdf
Defensive patterns

Strategy: validation

Validate before calling

// after reading Path= yourself, sanity-check before relying on it:
let decoded: std::path::PathBuf = /* percent-decoded Path= value */;
if decoded.file_name().is_none() {
    // original location is unusable ("/", ".."); skip or repair the .trashinfo
}

Type guard

fn has_terminal_file_name(p: &std::path::Path) -> bool {
    p.file_name().is_some_and(|n| !n.is_empty())
}

Try / catch

match trash.entry(&id) {
    Ok(e) => { /* ... */ }
    Err(e) if e.kind() == io::ErrorKind::InvalidData => { /* Path= is "/" or "..": edit or delete the .trashinfo */ }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A `.trashinfo` whose `Path=` value decodes to `/` or `..` (or `foo/..`); hand-edited or maliciously crafted trash metadata.

Common situations: Corrupted metadata after partial writes; trash info written by non-conformant tools; users editing `.trashinfo` files by hand.

Related errors


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