{"record":{"id":"8ffeac7790f67653","repo":"sxyazi/yazi","slug":"invalid-trash-item-path","errorCode":null,"errorMessage":"invalid trash item path","messagePattern":"invalid trash item path","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"yazi-fs/src/trash/entry.rs","lineNumber":43,"sourceCode":"\tfn deref(&self) -> &Self::Target { &self.id }\n}\n\nimpl TrashEntry {\n\t#[cfg(trash_unix)]\n\tpub(super) fn new<B>(id: TrashId, backing: B, original: Option<PathBuf>) -> io::Result<Self>\n\twhere\n\t\tB: Into<PathBuf>,\n\t{\n\t\tuse super::TrashCha;\n\t\tlet backing = backing.into();\n\n\t\tlet name = id\n\t\t\t.rel()\n\t\t\t.file_name()\n\t\t\t.or_else(|| original.as_deref().and_then(Path::file_name))\n\t\t\t.or_else(|| backing.file_name())\n\t\t\t.filter(|name| !name.is_empty())\n\t\t\t.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, \"invalid trash item path\"))?;\n\n\t\tlet (lcha, cha) = Cha::from_trash(&backing, name)?;\n\t\tlet link_to = if lcha.is_link() { std::fs::read_link(&backing).ok() } else { None };\n\n\t\tOk(Self { id, cha, lcha, original, link_to, backing })\n\t}\n\n\t#[cfg(trash_unix)]\n\tpub(super) fn top<T, B>(top: T, backing: B, original: Option<PathBuf>) -> io::Result<Self>\n\twhere\n\t\tT: Into<PathBuf>,\n\t\tB: Into<PathBuf>,\n\t{\n\t\tSelf::new(TrashId::new(top, PathBuf::new())?, backing, original)\n\t}\n\n\t#[cfg(trash_unix)]\n\tpub(super) fn child(&self, name: OsString) -> io::Result<Self> {","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/sxyazi/yazi/blob/94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2/yazi-fs/src/trash/entry.rs#L25-L61","documentation":"`TrashEntry::new` (yazi-fs/src/trash/entry.rs:43) needs a display/stat name for the entry and tries three sources in order: the file name of the id's relative path, the original put-back path's file name, then the backing path's file name. If all three are missing or empty (e.g. paths ending in `..` or empty), it fails with `ErrorKind::InvalidInput`, `invalid trash item path`.","triggerScenarios":"Building a `TrashEntry` from a `TrashId` whose `rel()` ends in `..` or is degenerate, while `original` is None and `backing` has no file name (e.g. `/` or `foo/..`). Also reachable via `TrashEntry::child()` when the child name is `..`-like.","commonSituations":"Hand-constructed or stale trash ids from plugins/Lua; trash metadata damaged so no original path is known and the backing file was removed.","solutions":["Only build entries from ids produced by the trash implementation itself (`Trash::list`/`entry`), never synthesize ids by hand.","Validate `id.rel()` is a plain relative path with a non-empty final component before calling.","Purge the damaged trash item (`rm` the backing file and its `.trashinfo`) so listing stops constructing it."],"exampleFix":"// before\nlet entry = TrashEntry::new(id, backing, None)?; // rel == \"..\" -> InvalidInput\n\n// after\nlet ok = id.rel().file_name().is_some_and(|n| !n.is_empty())\n    || backing.file_name().is_some_and(|n| !n.is_empty());\nif !ok { /* skip this damaged item */ }\nlet entry = TrashEntry::new(id, backing, None)?;","handlingStrategy":"validation","validationCode":"fn has_any_name(id: &TrashId, original: Option<&std::path::Path>, backing: &std::path::Path) -> bool {\n    let nonempty = |n: Option<&std::ffi::OsStr>| n.is_some_and(|n| !n.is_empty());\n    nonempty(id.rel().file_name())\n        || original.and_then(std::path::Path::file_name).is_some_and(|n| !n.is_empty())\n        || nonempty(backing.file_name())\n}","typeGuard":"fn is_usable_trash_id(id: &TrashId, backing: &std::path::Path) -> bool {\n    id.rel().file_name().is_some_and(|n| !n.is_empty())\n        || backing.file_name().is_some_and(|n| !n.is_empty())\n}","tryCatchPattern":"match TrashEntry::new(id, backing, original) {\n    Ok(e) => { /* ... */ }\n    Err(e) if e.kind() == io::ErrorKind::InvalidInput => { /* drop the damaged id; continue listing */ }\n    Err(e) => return Err(e),\n}","preventionTips":["Never synthesize TrashIds by string concatenation; take them from Trash::list/entry.","Reject ids whose rel() ends in `..` before use.","When listing trash, tolerate per-item InvalidInput and skip damaged entries instead of failing the listing."],"tags":["trash","entry","invalid-input","path-validation"],"backgroundTag":null,"analyzedSha":"94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2","analyzedAt":"2026-08-16T09:56:24.836Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}