{"record":{"id":"998349e4b4f54bf4","repo":"sxyazi/yazi","slug":"invalid-original-trash-path","errorCode":null,"errorMessage":"invalid original trash path","messagePattern":"invalid original trash path","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"yazi-fs/src/trash/freedesktop/trash_info.rs","lineNumber":36,"sourceCode":"\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}\n\n\t\tOk(Self { root: root.to_owned(), backing: root.join(\"files\").join(stem), original })\n\t}\n\n\tfn parse_original(info: &Path, root: &Path) -> io::Result<PathBuf> {\n\t\tlet mut reader = BufReader::new(File::open(info)?);\n\t\tlet mut line = Vec::new();\n\n\t\treader.read_until(b'\\n', &mut line)?;\n\t\tSelf::trim_line(&mut line);\n\t\tif line != b\"[Trash Info]\" {\n\t\t\treturn Err(io::Error::new(io::ErrorKind::InvalidData, \"invalid trash info header\"));\n\t\t}\n\n\t\tloop {\n\t\t\tline.clear();\n\t\t\tif reader.read_until(b'\\n', &mut line)? == 0 {","sourceCodeStart":18,"sourceCodeEnd":54,"githubUrl":"https://github.com/sxyazi/yazi/blob/94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2/yazi-fs/src/trash/freedesktop/trash_info.rs#L18-L54","documentation":"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.","triggerScenarios":"A `.trashinfo` whose `Path=` value decodes to `/` or `..` (or `foo/..`); hand-edited or maliciously crafted trash metadata.","commonSituations":"Corrupted metadata after partial writes; trash info written by non-conformant tools; users editing `.trashinfo` files by hand.","solutions":["Edit the `.trashinfo` and set `Path=` to the real absolute original location (e.g. `Path=/home/alice/report.pdf`).","Delete the broken `.trashinfo` (and its orphaned backing file in `files/`) if the original location is unknown.","If you generate trash metadata, always write absolute paths with a final component."],"exampleFix":"# before (~/.local/share/Trash/info/x.trashinfo)\n[Trash Info]\nPath=/\n\n# after\n[Trash Info]\nPath=/home/alice/report.pdf","handlingStrategy":"validation","validationCode":"// after reading Path= yourself, sanity-check before relying on it:\nlet decoded: std::path::PathBuf = /* percent-decoded Path= value */;\nif decoded.file_name().is_none() {\n    // original location is unusable (\"/\", \"..\"); skip or repair the .trashinfo\n}","typeGuard":"fn has_terminal_file_name(p: &std::path::Path) -> bool {\n    p.file_name().is_some_and(|n| !n.is_empty())\n}","tryCatchPattern":"match trash.entry(&id) {\n    Ok(e) => { /* ... */ }\n    Err(e) if e.kind() == io::ErrorKind::InvalidData => { /* Path= is \"/\" or \"..\": edit or delete the .trashinfo */ }\n    Err(e) => return Err(e),\n}","preventionTips":["When writing .trashinfo files, always store the absolute original path.","Treat Path=/ or Path=.. entries as corrupt; repair or purge them.","Validate any hand-edited trash metadata with a file_name check before restore."],"tags":["trash","trashinfo","path-validation","invalid-data"],"backgroundTag":null,"analyzedSha":"94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2","analyzedAt":"2026-08-16T09:56:24.836Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}