{"record":{"id":"e17d8f090a3c7161","repo":"sxyazi/yazi","slug":"invalid-trash-put-back-name","errorCode":null,"errorMessage":"invalid trash put-back name","messagePattern":"invalid trash put-back name","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"warning","filePath":"yazi-fs/src/trash/macos/ds_store.rs","lineNumber":51,"sourceCode":"\t\tOk(locations)\n\t}\n\n\tpub(super) fn join(&self, rel: &Path) -> io::Result<PathBuf> {\n\t\tif !rel.is_relative() || rel.has_parent_component() {\n\t\t\treturn Err(io::Error::new(io::ErrorKind::InvalidInput, \"invalid trash entry path\"));\n\t\t}\n\n\t\tlet parent = self.parent.as_deref().ok_or_else(|| {\n\t\t\tio::Error::new(io::ErrorKind::InvalidData, \"trash item has no put-back location\")\n\t\t})?;\n\n\t\tlet name = self.name.as_deref().ok_or_else(|| {\n\t\t\tio::Error::new(io::ErrorKind::InvalidData, \"trash item has no put-back name\")\n\t\t})?;\n\n\t\tlet mut components = Path::new(name).components();\n\t\tif !matches!(components.next(), Some(Component::Normal(_))) || components.next().is_some() {\n\t\t\treturn Err(io::Error::new(io::ErrorKind::InvalidData, \"invalid trash put-back name\"));\n\t\t}\n\n\t\tlet top_path = Path::new(\"/\").join(parent).join(name);\n\t\tOk(if rel.as_os_str().is_empty() { top_path } else { top_path.join(rel) })\n\t}\n}\n","sourceCodeStart":33,"sourceCodeEnd":58,"githubUrl":"https://github.com/sxyazi/yazi/blob/94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2/yazi-fs/src/trash/macos/ds_store.rs#L33-L58","documentation":"Thrown by DsStore::join on macOS when the ptbN put-back name parsed from ~/.Trash/.DS_Store is not a single normal path component (e.g. '/', '..', 'a/b'). This is a validation step that prevents path traversal or malformed joins before constructing the original path. The error is swallowed with .ok() upstream, leaving the entry without put-back info.","triggerScenarios":"The ptbN Ustr value fails the components() check: first component is RootDir/ParentDir/CurDir, or there is more than one component (name contains a separator).","commonSituations":"Corrupted or hand-edited .DS_Store; maliciously crafted .DS_Store aiming at path traversal; metadata written by non-Finder tools with unsanitized names.","solutions":["Treat the item as manually restorable: move it out of ~/.Trash yourself or use Trash:rename with an explicit destination.","Delete or rebuild ~/.Trash/.DS_Store (Finder recreates it) so future records parse cleanly.","If you parse .DS_Store yourself, validate put-back names the same way (exactly one Component::Normal) before joining."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"-- The library already validates ptbN; you only see original == nil.\nlocal safe = {}\nfor _, e in ipairs(entries) do\n  if e.original ~= nil then table.insert(safe, e) end\nend","typeGuard":"local function is_restorable(e) return e.original ~= nil end","tryCatchPattern":"if not trash:restore(safe) then -- fall back to manual move via Trash:rename with an explicit destination end","preventionTips":["Trust the library's traversal guard; never reconstruct original paths from raw .DS_Store values.","If .DS_Store is suspected corrupt, let Finder recreate it (delete while Finder is closed).","Screen for original == nil in restore flows."],"tags":["trash","macos","ds-store","put-back","path-traversal","validation"],"backgroundTag":null,"analyzedSha":"94abcfa92f4ad3f0a1aef6c1ea083cfb8aa6c8c2","analyzedAt":"2026-08-16T09:56:24.836Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}