sxyazi/yazi · error · io::Error
invalid trash info path
Error message
invalid trash info path
What it means
`TrashInfo::parse` (freedesktop/trash_info.rs:19) requires its input path to end with the literal extension `.trashinfo`; anything else is rejected with `ErrorKind::InvalidData`, `invalid trash info path`. The extension is what maps an id to its metadata file under `<trash-root>/info/`.
Source
Thrown at yazi-fs/src/trash/freedesktop/trash_info.rs:19
use std::{borrow::Cow, ffi::OsStr, fs::File, io::{self, BufRead, BufReader}, os::unix::ffi::OsStrExt, path::{Path, PathBuf}};
use percent_encoding::percent_decode;
use uzers::Users;
use yazi_shared::USERS_CACHE;
use yazi_shim::path::PathExt;
pub(super) struct TrashInfo {
pub(super) root: PathBuf,
pub(super) backing: PathBuf,
pub(super) original: PathBuf,
}
impl TrashInfo {
// Parses from a trashinfo path, e.g.:
// /home/alice/.local/share/Trash/info/cat.jpg.trashinfo
pub(super) fn parse(info: &Path) -> io::Result<Self> {
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"));
}View on GitHub (pinned to 94abcfa92f)
Solutions
- Only use ids returned by `Trash::list`/`tops`; their tops always carry the `.trashinfo` extension.
- If constructing ids, build them as `<trash_root>/info/<stem>.trashinfo`.
- Validate `path.extension() == Some("trashinfo")` before passing an id top to `entry()`.
Example fix
// before
let entry = trash.entry(&id)?; // id.top() == ".../files/cat.jpg" -> InvalidData
// after
let top = id.top();
if top.extension() != Some(OsStr::new("trashinfo")) { /* rebuild id from list() */ }
let entry = trash.entry(&id)?; Defensive patterns
Strategy: validation
Validate before calling
use std::ffi::OsStr;
if id.top().extension() != Some(OsStr::new("trashinfo")) {
// rebuild the id from trash.list() instead of proceeding
} Type guard
fn is_trashinfo_path(p: &std::path::Path) -> bool {
p.extension() == Some(std::ffi::OsStr::new("trashinfo"))
} Try / catch
match trash.entry(&id) {
Ok(e) => { /* ... */ }
Err(e) if e.kind() == io::ErrorKind::InvalidData => { /* id top is not a .trashinfo path */ }
Err(e) => return Err(e),
} Prevention
- Take ids only from the trash listing API; never construct tops by hand.
- If you must build one, template it as `<trash_root>/info/<stem>.trashinfo`.
- Validate the extension before calling entry() in plugin code.
When it happens
Trigger: Calling `Trash::entry(&id)` where `id.top()` is a path without the `.trashinfo` extension — a path into `files/`, the trash root itself, or an arbitrary file.
Common situations: Hand-built `TrashId`s; string manipulation that strips or mangles the extension; passing the backing (files/) path where the info path was intended.
Related errors
- invalid original trash path
- invalid trash info header
- trash info has no Path
- invalid trash mount point
- invalid trash item path
AI-assisted analysis of sxyazi/yazi@94abcfa92f (2026-08-16).
Data as JSON: /api/errors/10a7a14300d8c29a.
Report an issue: GitHub.