{"record":{"id":"e498470d27538cee","repo":"Hmbown/CodeWhale","slug":"restore-refuses-directories-symlinks-and-non-regular-files","errorCode":null,"errorMessage":"restore refuses directories, symlinks and non-regular files","messagePattern":"restore refuses directories, symlinks and non-regular files","errorType":"validation","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/snapshot/repo.rs","lineNumber":656,"sourceCode":"        {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                format!(\n                    \"refusing to restore unsafe path '{}': restore requires a regular workspace file\",\n                    rel.display()\n                ),\n            ));\n        }\n        let mut path = self.work_tree.clone();\n        for part in rel.components() {\n            path.push(part);\n            match std::fs::symlink_metadata(&path) {\n                Ok(meta)\n                    if meta.file_type().is_symlink()\n                        || (path == self.work_tree.join(rel) && !meta.is_file())\n                        || (path != self.work_tree.join(rel) && !meta.is_dir()) =>\n                {\n                    return Err(io::Error::new(\n                        io::ErrorKind::InvalidInput,\n                        \"restore refuses directories, symlinks and non-regular files\",\n                    ));\n                }\n                Ok(_) => {}\n                Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(false),\n                Err(error) => return Err(error),\n            }\n        }\n        Ok(true)\n    }\n\n    fn snapshot_contains_regular_file(&self, id: &SnapshotId, rel: &Path) -> io::Result<bool> {\n        let entry = run_git(\n            &self.git_dir,\n            &self.work_tree,\n            &[\n                \"--literal-pathspecs\",","sourceCodeStart":638,"sourceCodeEnd":674,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/snapshot/repo.rs#L638-L674","documentation":"The second half of validate_restore_file checks the on-disk file type at the restore target (symlink_metadata, so symlinks are detected without following). A symlink, a directory where the workspace path is expected, or a non-regular/non-directory entry (fifo, socket, device) anywhere in the path is refused: restore only handles plain workspace files. NotFound is treated as \"nothing to restore\" (Ok(false)), not an error.","triggerScenarios":"Restoring a path where the workspace target is a symlink, a directory (when restoring into the work tree), or a special file; or where a parent component is not a regular directory.","commonSituations":"Workspace switched branches and a formerly-regular file became a symlink; user replaced a file with a directory; project uses symlinked source files; leftover named pipes from build tooling.","solutions":["Replace the symlink/special file with a regular file (or remove it) before restoring.","Remove the directory occupying the target path if a file should be restored there.","Re-check workspace state (e.g. after a branch switch) and refresh the change record, then retry."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn restorable_target(ws: &Path, rel: &Path) -> bool {\n    match std::fs::symlink_metadata(ws.join(rel)) {\n        Ok(m) => m.is_file() && !m.file_type().is_symlink(),\n        Err(_) => true, // NotFound is fine: nothing to overwrite\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check symlink_metadata on targets before scripted restores.","Remove or replace symlinks/special files with regular files first.","Re-verify workspace state after branch switches that may swap file types."],"tags":["restore","filesystem","symlink"],"backgroundTag":"incompatible-source-type","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}