sxyazi/yazi · error · io::Error

invalid trash info header

Error message

invalid trash info header

What it means

`TrashInfo::parse_original` (trash_info.rs:49) reads the first line of the `.trashinfo` file and requires it to be exactly `[Trash Info]` (after trimming trailing CR/LF). Any other first line — a different header, a BOM, garbage bytes — yields `ErrorKind::InvalidData`, `invalid trash info header`.

Source

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

			.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 {
				return Err(io::Error::new(io::ErrorKind::InvalidData, "trash info has no Path"));
			}

			Self::trim_line(&mut line);
			let Some(value) = line.strip_prefix(b"Path=") else { continue };
			let decoded: Cow<[u8]> = percent_decode(value).into();

			let path = Path::new(OsStr::from_bytes(decoded.as_ref()));
			if path.as_os_str().is_empty() || !path.is_absolute() && path.has_parent_component() {
				return Err(io::Error::new(io::ErrorKind::InvalidData, "invalid original trash path"));
			}

			return Ok(if path.is_absolute() {

View on GitHub (pinned to 94abcfa92f)

Solutions

  1. Fix the file: make line 1 exactly `[Trash Info]`, with no leading BOM or whitespace.
  2. If the file is junk, delete it together with its backing entry in `files/`.
  3. Regenerate the `.trashinfo` with correct `Path=`/`DeletionDate=` if you know the original location.

Example fix

# before (hex: EF BB BF 5B ... = BOM before header)
[Trash Info]
Path=/home/alice/cat.jpg

# after
[Trash Info]
Path=/home/alice/cat.jpg
Defensive patterns

Strategy: try-catch

Validate before calling

// quick pre-check when operating on .trashinfo files directly:
fn has_valid_header(p: &std::path::Path) -> std::io::Result<bool> {
    use std::io::BufRead;
    let mut line = Vec::new();
    std::io::BufReader::new(std::fs::File::open(p)?).read_until(b'\n', &mut line)?;
    while matches!(line.last(), Some(b'\n' | b'\r')) { line.pop(); }
    Ok(line == b"[Trash Info]")
}

Try / catch

match trash.entry(&id) {
    Ok(e) => { /* ... */ }
    Err(e) if e.kind() == io::ErrorKind::InvalidData => {
        // header corrupted: rewrite line 1 as exactly "[Trash Info]" (no BOM), or delete the file
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Opening (via `Trash::entry`) a `.trashinfo` whose first line is not the INI section header: text editors saving with a UTF-8 BOM, files truncated at the top, or non-trash files merely named `*.trashinfo`.

Common situations: Hand-edited metadata saved by editors that add BOMs or re-encode; partially overwritten files after a crash; a random file renamed to `.trashinfo`.

Related errors


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