{"record":{"id":"10a7a14300d8c29a","repo":"sxyazi/yazi","slug":"invalid-trash-info-path","errorCode":null,"errorMessage":"invalid trash info path","messagePattern":"invalid trash info path","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"yazi-fs/src/trash/freedesktop/trash_info.rs","lineNumber":19,"sourceCode":"use std::{borrow::Cow, ffi::OsStr, fs::File, io::{self, BufRead, BufReader}, os::unix::ffi::OsStrExt, path::{Path, PathBuf}};\n\nuse percent_encoding::percent_decode;\nuse uzers::Users;\nuse yazi_shared::USERS_CACHE;\nuse yazi_shim::path::PathExt;\n\npub(super) struct TrashInfo {\n\tpub(super) root:     PathBuf,\n\tpub(super) backing:  PathBuf,\n\tpub(super) original: PathBuf,\n}\n\nimpl TrashInfo {\n\t// Parses from a trashinfo path, e.g.:\n\t//   /home/alice/.local/share/Trash/info/cat.jpg.trashinfo\n\tpub(super) fn parse(info: &Path) -> io::Result<Self> {\n\t\tif info.extension() != Some(OsStr::new(\"trashinfo\")) {\n\t\t\treturn Err(io::Error::new(io::ErrorKind::InvalidData, \"invalid trash info path\"));\n\t\t}\n\n\t\t// /home/alice/.local/share/Trash\n\t\tlet root = info\n\t\t\t.parent()\n\t\t\t.filter(|p| p.file_name() == Some(OsStr::new(\"info\")))\n\t\t\t.and_then(Path::parent)\n\t\t\t.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, \"invalid trash info path\"))?;\n\n\t\t// cat.jpg\n\t\tlet stem = info\n\t\t\t.file_stem()\n\t\t\t.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidData, \"invalid trash info path\"))?;\n\n\t\tlet original = Self::parse_original(info, root)?;\n\t\tif original.file_name().is_none() {\n\t\t\treturn Err(io::Error::new(io::ErrorKind::InvalidData, \"invalid original trash path\"));\n\t\t}","sourceCodeStart":1,"sourceCodeEnd":37,"githubUrl":"https://github.com/sxyazi/yazi/blob/94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2/yazi-fs/src/trash/freedesktop/trash_info.rs#L1-L37","documentation":"`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/`.","triggerScenarios":"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.","commonSituations":"Hand-built `TrashId`s; string manipulation that strips or mangles the extension; passing the backing (files/) path where the info path was intended.","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()`."],"exampleFix":"// before\nlet entry = trash.entry(&id)?; // id.top() == \".../files/cat.jpg\" -> InvalidData\n\n// after\nlet top = id.top();\nif top.extension() != Some(OsStr::new(\"trashinfo\")) { /* rebuild id from list() */ }\nlet entry = trash.entry(&id)?;","handlingStrategy":"validation","validationCode":"use std::ffi::OsStr;\n\nif id.top().extension() != Some(OsStr::new(\"trashinfo\")) {\n    // rebuild the id from trash.list() instead of proceeding\n}","typeGuard":"fn is_trashinfo_path(p: &std::path::Path) -> bool {\n    p.extension() == Some(std::ffi::OsStr::new(\"trashinfo\"))\n}","tryCatchPattern":"match trash.entry(&id) {\n    Ok(e) => { /* ... */ }\n    Err(e) if e.kind() == io::ErrorKind::InvalidData => { /* id top is not a .trashinfo path */ }\n    Err(e) => return Err(e),\n}","preventionTips":["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."],"tags":["trash","trashinfo","freedesktop","invalid-data","path-validation"],"backgroundTag":null,"analyzedSha":"94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2","analyzedAt":"2026-08-16T09:56:24.836Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}