can1357/oh-my-pi · error
target {0}: Not a directory
Error message
target {0}: Not a directory What it means
This is MvError::NotADirectory from crates/pi-builtins/src/mv.rs. Raised in `move_files_into_dir` (mv.rs:785-787) when the multi-operand form of mv resolves its target directory and finds it is not a directory: `mv src... target_dir` or `mv -t DIR src...` with a non-directory final operand. In GNU mv, a non-existent destination directory is simply created only for a single rename; for the many-to-one form the last operand must already be a directory, so the builtin reports this error instead.
Source
Thrown at crates/pi-builtins/src/mv.rs:65
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),
}
type MvResult<T> = Result<T, MvFailure>;View on GitHub (pinned to 9690622007)
Solutions
- Create the target directory before the move: `mkdir -p dest`.
- Verify the last operand is the intended directory (`ls -ld dest`) and fix typos.
- If you actually want a rename (single source to a new name), use the two-operand form `mv src dest` rather than many-to-one.
- Resolve any symlink standing in for the target and point the command at the real directory.
Example fix
// before (fails: backups is not a directory) mv file1 file2 backups // after mkdir -p backups && mv file1 file2 backups/
Defensive patterns
Strategy: validation
Validate before calling
import * as fs from "node:fs/promises";
export async function ensureTargetDir(dir: string): Promise<string> {
const st = await fs.stat(dir).catch(() => null);
if (!st?.isDirectory()) {
await fs.mkdir(dir, { recursive: true });
}
return dir;
}
// await ensureTargetDir(dest); then mv src... dest Try / catch
try {
await runBuiltin("mv", [...sources, dest]);
} catch (e) {
if (String(e).startsWith("target ") && String(e).includes("Not a directory")) {
await fs.mkdir(dest, { recursive: true });
await runBuiltin("mv", [...sources, dest]); // retry once
} else throw e;
} Prevention
- Always mkdir -p the destination directory before a many-to-one mv.
- Keep the target directory as an explicit, verified variable, not a trailing glob result.
- Check for typos: a misspelled directory silently resolves to 'not a directory'.
- Remember mv only auto-creates the destination for a single-source rename, never for multiple sources.
When it happens
Trigger: `mv a b c dest` where dest does not exist or is a regular file; `mv -t somefile src1 src2` where somefile is not a directory; `mv -t nonexistent src` (target directory never created); a symlink as target whose link target is a file.
Common situations: Batch-move scripts where the destination directory was never `mkdir -p`'d; typos in the directory name so it resolves to nothing; build scripts expecting a directory that a previous step failed to create; glob expansion producing a file as the final argument.
Related errors
- target directory {0}: Not a directory
- failed to create {} via template {}: No such file or directo
- cannot stat {0}: No such file or directory
- cannot stat {0}: Not a directory
- {0} and {1} are the same file
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/af04cc6734c15fdf.
Report an issue: GitHub.