Hmbown/CodeWhale · error · io::Error
restore refuses directories, symlinks and non-regular files
Error message
restore refuses directories, symlinks and non-regular files
What it means
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.
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.
Defensive patterns
Strategy: validation
Validate before calling
fn restorable_target(ws: &Path, rel: &Path) -> bool {
match std::fs::symlink_metadata(ws.join(rel)) {
Ok(m) => m.is_file() && !m.file_type().is_symlink(),
Err(_) => true, // NotFound is fine: nothing to overwrite
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.
Related errors
- built-in plugin path may not be a symbolic link or reparse…
- CodewhalePet/1
- could not securely open
- external credential path must name a non-reparse regular…
- failed to create owned skill directory
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/e498470d27538cee.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/snapshot/repo.rs:656
{
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!(
"refusing to restore unsafe path '{}': restore requires a regular workspace file",
rel.display()
),
));
}
let mut path = self.work_tree.clone();
for part in rel.components() {
path.push(part);
match std::fs::symlink_metadata(&path) {
Ok(meta)
if meta.file_type().is_symlink()
|| (path == self.work_tree.join(rel) && !meta.is_file())
|| (path != self.work_tree.join(rel) && !meta.is_dir()) =>
{
return Err(io::Error::new(
io::ErrorKind::InvalidInput,
"restore refuses directories, symlinks and non-regular files",
));
}
Ok(_) => {}
Err(error) if error.kind() == io::ErrorKind::NotFound => return Ok(false),
Err(error) => return Err(error),
}
}
Ok(true)
}
fn snapshot_contains_regular_file(&self, id: &SnapshotId, rel: &Path) -> io::Result<bool> {
let entry = run_git(
&self.git_dir,
&self.work_tree,
&[
"--literal-pathspecs",View on GitHub (pinned to 73e0f67d83)