can1357/oh-my-pi · error
cannot overwrite directory {0} with non-directory
Error message
cannot overwrite directory {0} with non-directory What it means
This is MvError::DirectoryToNonDirectory in crates/pi-builtins/src/mv.rs. It is raised when the destination path already exists and is a directory, but the source is a non-directory file — so mv would have to replace a directory with a file, which the kernel rename cannot do and coreutils forbids. Triggered from `handle_two_paths` (mv.rs:609-621) when `-T/--no-target-directory` is used with a directory target, or via the equivalent branch when target exists as a dir. Note the payload is the target path, matching GNU mv's message.
Source
Thrown at crates/pi-builtins/src/mv.rs:61
use crate::host::{Host, Utility, format_usage, matches_parser, util};
#[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}")]View on GitHub (pinned to 9690622007)
Solutions
- Remove or rename the existing directory first if it is truly meant to be replaced, then re-run the move.
- Drop the `-T` flag if the intent was to move the source INTO the directory (`mv file dir/`).
- Check the destination with `ls -ld dest` to confirm its type before scripting the move.
- If the directory should hold the file, move to `dest/basename` instead of overwriting `dest` itself.
Example fix
// before (fails: conf is a directory) mv -T config.yaml conf // after: move the file into the directory mv config.yaml conf/config.yaml // or, to truly replace the directory: rm -rf conf && mv config.yaml conf
Defensive patterns
Strategy: validation
Validate before calling
import * as fs from "node:fs/promises";
export async function safeMoveFileOver(src: string, dest: string): Promise<void> {
const st = await fs.lstat(dest).catch(() => null);
if (st?.isDirectory()) {
throw new Error(`destination ${dest} is a directory; move into it or remove it first`);
}
// proceed with mv src dest (-T semantics)
} Try / catch
try {
await runBuiltin("mv", ["-T", src, dest]);
} catch (e) {
if (String(e).includes("cannot overwrite directory")) {
logger.error("destination is an existing directory", { dest });
} else throw e;
} Prevention
- Stat the destination and branch on isDirectory() before every scripted move.
- Avoid -T unless you are certain the destination is a regular file.
- Don't mkdir -p a path you later intend to overwrite with a file.
- Clean stale directories left by earlier build/setup steps before moving files onto them.
When it happens
Trigger: `mv -T somefile existing_dir` (file over an existing directory); `mv --no-target-directory file dir_that_exists`; mv invoked with a symlink that resolves to a directory as the second operand while the source is a plain file and -T is set.
Common situations: Scripts that assumed the destination was a regular file but a directory of that name was created earlier (e.g. by `mkdir -p` in setup); users typing `mv -T newfile conf` where `conf/` is a config directory; build tooling that switched between file and directory outputs across versions, leaving a stale directory in place.
Related errors
- cannot overwrite non-directory {1} with directory {0}
- 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/b038e8dcac41eb40.
Report an issue: GitHub.