can1357/oh-my-pi · error
failed to access {0}: Not a directory
Error message
failed to access {0}: Not a directory What it means
This error from the built-in `mv` utility (MvError::FailedToAccessNotADirectory) means the target path was treated as a directory, but some component of it is not a directory, so the move cannot be performed. It mirrors GNU coreutils' `mv: failed to access 'X': Not a directory` diagnostic. It is thrown when the source and target are both non-directories and the target operand ends with a path terminator (a trailing `/` or `/.`), signaling the user expects a directory that does not exist as one.
Source
Thrown at crates/pi-builtins/src/mv.rs:69
#[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>;
/// Parsed `mv` invocation.
pub(crate) struct Mv {
matches: ArgMatches,View on GitHub (pinned to 9690622007)
Solutions
- Create the destination directory first (mkdir -p dest) before running mv
- Remove the trailing slash from the target if you actually want to rename the source to that name
- Check with `ls -ld dest` whether the target exists and is a directory; fix the path if it is a file
- Use `mv -T source.txt dest` (no-target-directory) if you intentionally want to rename onto the plain name
Example fix
// before mv results.txt build/out/ // error: failed to access 'build/out/': Not a directory // after mkdir -p build/out && mv results.txt build/out/
Defensive patterns
Strategy: validation
Validate before calling
import * as fs from "node:fs";
function ensureTargetDirUsable(target: string): boolean {
if (!target.endsWith("/")) return true; // plain rename, no dir expectation
const dir = target.replace(/\/+$/, "");
return fs.existsSync(dir) && fs.statSync(dir).isDirectory();
}
if (!ensureTargetDirUsable(dest)) mkdirSync(dest, { recursive: true }); Try / catch
try {
await run("mv", [src, dest]);
} catch (err) {
if (String(err.stderr).includes("failed to access") && String(err.stderr).includes("Not a directory")) {
await fs.mkdir(dest.replace(/\/+$/, ""), { recursive: true });
await run("mv", [src, dest]);
} else throw err;
} Prevention
- Run `ls -ld target` to confirm the destination exists and is a directory before moving
- Never append a trailing slash unless you have verified the target is a directory
- Use mkdir -p on the destination directory as a standard pre-step in scripts
- Prefer mv -T when you intend a plain rename, avoiding directory semantics entirely
When it happens
Trigger: Running `mv source.txt dest/` (or `dest/.`) where `dest` does not exist or is a regular file, with the two-path handler in handle_two_paths (mv.rs:598-604): the target ends with a terminator, target_is_dir is false, source is not a directory, and neither --no-target-directory (-T) nor update=older is in effect.
Common situations: Typo in the destination directory name (`mv a.txt outpt/` when the dir is `output`); expecting a directory to exist that a previous mkdir/create step skipped; pointing at a regular file with a trailing slash; CI scripts assuming a build-output directory exists.
Related errors
- cannot access {}: Not a 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/5e136d097c8128bd.
Report an issue: GitHub.