{"record":{"id":"5e136d097c8128bd","repo":"can1357/oh-my-pi","slug":"failed-to-access-0-not-a-directory","errorCode":null,"errorMessage":"failed to access {0}: Not a directory","messagePattern":"failed to access (.+?): Not a directory","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/pi-builtins/src/mv.rs","lineNumber":69,"sourceCode":"#[derive(Debug, Error)]\nenum MvError {\n\t#[error(\"cannot stat {0}: No such file or directory\")]\n\tNoSuchFile(String),\n\t#[error(\"cannot stat {0}: Not a directory\")]\n\tCannotStatNotADirectory(String),\n\t#[error(\"{0} and {1} are the same file\")]\n\tSameFile(String, String),\n\t#[error(\"cannot move {0} to a subdirectory of itself, {1}\")]\n\tSelfTargetSubdirectory(String, String),\n\t#[error(\"cannot overwrite directory {0} with non-directory\")]\n\tDirectoryToNonDirectory(String),\n\t#[error(\"cannot overwrite non-directory {1} with directory {0}\")]\n\tNonDirectoryToDirectory(String, String),\n\t#[error(\"target {0}: Not a directory\")]\n\tNotADirectory(String),\n\t#[error(\"target directory {0}: Not a directory\")]\n\tTargetNotADirectory(String),\n\t#[error(\"failed to access {0}: Not a directory\")]\n\tFailedToAccessNotADirectory(String),\n}\n\n#[derive(Debug, Error)]\nenum MvFailure {\n\t#[error(transparent)]\n\tMove(#[from] MvError),\n\t#[error(transparent)]\n\tIo(#[from] io::Error),\n\t#[error(\"{0}\")]\n\tMessage(String),\n}\n\ntype MvResult<T> = Result<T, MvFailure>;\n\n/// Parsed `mv` invocation.\npub(crate) struct Mv {\n\tmatches: ArgMatches,","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/crates/pi-builtins/src/mv.rs#L51-L87","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nmv results.txt build/out/\n// error: failed to access 'build/out/': Not a directory\n// after\nmkdir -p build/out && mv results.txt build/out/","handlingStrategy":"validation","validationCode":"import * as fs from \"node:fs\";\nfunction ensureTargetDirUsable(target: string): boolean {\n  if (!target.endsWith(\"/\")) return true; // plain rename, no dir expectation\n  const dir = target.replace(/\\/+$/, \"\");\n  return fs.existsSync(dir) && fs.statSync(dir).isDirectory();\n}\nif (!ensureTargetDirUsable(dest)) mkdirSync(dest, { recursive: true });","typeGuard":null,"tryCatchPattern":"try {\n  await run(\"mv\", [src, dest]);\n} catch (err) {\n  if (String(err.stderr).includes(\"failed to access\") && String(err.stderr).includes(\"Not a directory\")) {\n    await fs.mkdir(dest.replace(/\\/+$/, \"\"), { recursive: true });\n    await run(\"mv\", [src, dest]);\n  } else throw err;\n}","preventionTips":["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"],"tags":["filesystem","mv","path","not-a-directory"],"backgroundTag":"not-a-directory","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}