can1357/oh-my-pi · error
cannot overwrite non-directory {1} with directory {0}
Error message
cannot overwrite non-directory {1} with directory {0} What it means
This is MvError::NonDirectoryToDirectory in crates/pi-builtins/src/mv.rs. Raised when the source is a directory (or non-file operand) and the destination already exists as a non-directory file — mv cannot replace a regular file with a directory. In `handle_two_paths` (mv.rs:626-641) this fires when `target_fs.exists() && source_is_dir` and the destination is not a directory, after the overwrite-mode prompt (declining an `-i` prompt also surfaces here). Format arguments: {0} is the source, {1} the destination.
Source
Thrown at crates/pi-builtins/src/mv.rs:63
#[cfg(unix)]
use self::hardlink::{
HardlinkGroupScanner, HardlinkOptions, HardlinkTracker, create_hardlink_context,
with_optional_hardlink_context,
};
#[derive(Debug, Error)]
enum MvError {
#[error("cannot stat {0}: No such file or directory")]
NoSuchFile(String),
#[error("cannot stat {0}: Not a directory")]
CannotStatNotADirectory(String),
#[error("{0} and {1} are the same file")]
SameFile(String, String),
#[error("cannot move {0} to a subdirectory of itself, {1}")]
SelfTargetSubdirectory(String, String),
#[error("cannot overwrite directory {0} with non-directory")]
DirectoryToNonDirectory(String),
#[error("cannot overwrite non-directory {1} with directory {0}")]
NonDirectoryToDirectory(String, String),
#[error("target {0}: Not a directory")]
NotADirectory(String),
#[error("target directory {0}: Not a directory")]
TargetNotADirectory(String),
#[error("failed to access {0}: Not a directory")]
FailedToAccessNotADirectory(String),
}
#[derive(Debug, Error)]
enum MvFailure {
#[error(transparent)]
Move(#[from] MvError),
#[error(transparent)]
Io(#[from] io::Error),
#[error("{0}")]
Message(String),
}View on GitHub (pinned to 9690622007)
Solutions
- Remove or rename the existing file first (`rm dest` or `mv dest dest.bak`) if the directory should replace it, then re-run mv.
- Verify operand order and target type: `file dest` / `ls -ld` to confirm the last argument is a directory.
- If the destination was meant to be a target directory, create it (`mkdir -p dest`) and move into it.
- Check for a symlink at the destination with `readlink dest` and correct or remove it.
Example fix
// before (fails: dest is a regular file)
mv srcdir dest
// after
dest_is_file && { mv dest dest.old; }
mv srcdir dest # or: mkdir -p dest && mv srcdir dest/srcdir Defensive patterns
Strategy: validation
Validate before calling
import * as fs from "node:fs/promises";
export async function moveDirIntoOrReplace(src: string, dest: string): Promise<void> {
const srcIsDir = (await fs.stat(src)).isDirectory();
const destSt = await fs.lstat(dest).catch(() => null);
if (srcIsDir && destSt && !destSt.isDirectory()) {
// decide explicitly: remove, back up, or pick a new destination
await fs.rename(dest, `${dest}.old`);
}
// proceed with mv
} Try / catch
try {
await runBuiltin("mv", [src, dest]);
} catch (e) {
if (String(e).includes("cannot overwrite non-directory")) {
logger.error("destination exists as a non-directory", { src, dest });
} else throw e;
} Prevention
- Confirm the last operand of a multi-source mv is an existing directory.
- Back up or remove a stale file at the destination before moving a directory there.
- Check for symlinks at destinations — a file symlink trips this error.
- Verify operand order in scripts when paths come from variables or globs.
When it happens
Trigger: `mv srcdir existing_file` where existing_file is a regular file or symlink-to-file; `mv -T srcdir existing_file`; multiple sources with a file as the final target directory operand; answering 'n' to an interactive overwrite prompt in this same branch.
Common situations: A path that used to be a directory was replaced by a symlink or file (stale checkout, tooling change); typos where the last argument is a file instead of the intended target directory; scripts that expected `dest/` to exist and got a file of the same name; package managers leaving a file where a directory is expected.
Related errors
- cannot overwrite directory {0} with non-directory
- cannot stat {0}: No such file or directory
- cannot stat {0}: Not a directory
- {0} and {1} are the same file
- cannot move {0} to a subdirectory of itself, {1}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/222cf7c89ab505bd.
Report an issue: GitHub.