{"record":{"id":"ea5b27f204b471ad","repo":"can1357/oh-my-pi","slug":"cannot-stat-0-not-a-directory","errorCode":null,"errorMessage":"cannot stat {0}: Not a directory","messagePattern":"cannot stat (.+?): Not a directory","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/pi-builtins/src/mv.rs","lineNumber":55,"sourceCode":"\tfs::{\n\t\tMissingHandling, ResolveMode, are_hardlinks_or_one_way_symlink_to_same_file,\n\t\tare_hardlinks_to_same_file, canonicalize, path_ends_with_terminator,\n\t},\n\tupdate_control::{self, UpdateMode},\n};\n\nuse crate::host::{Host, Utility, format_usage, matches_parser, util};\n#[cfg(unix)]\nuse self::hardlink::{\n\tHardlinkGroupScanner, HardlinkOptions, HardlinkTracker, create_hardlink_context,\n\twith_optional_hardlink_context,\n};\n\n#[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)]","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/crates/pi-builtins/src/mv.rs#L37-L73","documentation":"GNU-compatible `mv` error (`MvError::CannotStatNotADirectory`, crates/pi-builtins/src/mv.rs:55). Same underlying condition as `NoSuchFile` — `symlink_metadata` failed on the source — but selected when the source operand ends with a trailing path separator (`path_ends_with_terminator`). The trailing `/` asserts the operand must be a directory, and stat on `foo/` fails with ENOTDIR rather than ENOENT on most platforms.","triggerScenarios":"`mv foo/ bar` where `foo` does not exist (or is a regular file, so `foo/` cannot name a directory) — the trailing slash triggers this variant in `handle_two_paths`.","commonSituations":"Tab-completed or copy-pasted paths that keep a trailing `/` after the target was renamed or deleted; scripts appending `/` to a directory variable that is empty or points at a file; shell scripts written expecting `foo/` to still resolve when `foo` is a symlink later removed.","solutions":["Check whether the path exists: `ls -ld foo` — if missing, create it or fix the variable that supplies it.","If the operand is actually a regular file, drop the trailing slash: `mv foo bar` instead of `mv foo/ bar`.","Guard directory operands: `[ -d \"$src\" ] && mv \"$src/\" \"$dst\"`.","Strip accidental trailing separators in scripts: `src=\"${src%/}\"`."],"exampleFix":"# before\nmv \"$build_dir/\" out/   # build_dir unset => mv / out/  -> cannot stat '/': Not a directory\n# after\n: \"${build_dir:?build_dir not set}\"\n[ -d \"$build_dir\" ] && mv \"$build_dir\" out/","handlingStrategy":"validation","validationCode":"src=\"${src%/}\"            # drop trailing separator\n[ -d \"$src\" ] || { echo \"mv: '$src' is not a directory\" >&2; exit 1; }","typeGuard":null,"tryCatchPattern":"if ! mv \"$src\" \"$dst\" 2>err.txt; then cat err.txt >&2; grep -q 'Not a directory' err.txt && exit 1; fi","preventionTips":["Strip trailing slashes from directory variables (`${var%/}`).","Only append `/` to operands you have verified are directories ([ -d ... ]).","Remember a trailing `/` requires the operand to exist as a directory — a plain file or missing path fails stat.","Expand and echo the final path (set -x) to catch empty variables that leave a lone `/`."],"tags":["filesystem","mv","path-separator","stat"],"backgroundTag":"not-a-directory","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}