{"record":{"id":"dfd8eb9e520ec67a","repo":"can1357/oh-my-pi","slug":"is-a-directory","errorCode":null,"errorMessage":"Is a directory","messagePattern":"Is a directory","errorType":"exception","errorClass":"CatError","httpStatus":null,"severity":"error","filePath":"crates/pi-builtins/src/cat.rs","lineNumber":78,"sourceCode":"\t}\n\n\tfn write(&self, writer: &mut impl Write) -> io::Result<()> {\n\t\twriter.write_all(self.to_str())\n\t}\n}\n\n#[derive(Error, Debug)]\nenum CatError {\n\t/// Wrapper around `io::Error`.\n\t#[error(\"{}\", strip_errno(.0))]\n\tIo(io::Error),\n\t/// The downstream reader closed its pipe; this ends the copy quietly.\n\t#[error(\"broken pipe\")]\n\tBrokenPipe,\n\t/// Unknown file type; it is not a regular file, socket, or known device.\n\t#[error(\"unknown filetype: {ft_debug}\")]\n\tUnknownFiletype { ft_debug: String },\n\t#[error(\"Is a directory\")]\n\tIsDirectory,\n\t#[cfg(unix)]\n\t#[error(\"No such device or address\")]\n\tNoSuchDeviceOrAddress,\n\t#[error(\"Too many levels of symbolic links\")]\n\tTooManySymlinks,\n}\n\nimpl From<io::Error> for CatError {\n\tfn from(error: io::Error) -> Self {\n\t\tif error.kind() == ErrorKind::BrokenPipe {\n\t\t\tSelf::BrokenPipe\n\t\t} else {\n\t\t\tSelf::Io(error)\n\t\t}\n\t}\n}\n","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/crates/pi-builtins/src/cat.rs#L60-L96","documentation":"`CatError::IsDirectory` reports that a `cat` argument is a directory, which cannot be read as a byte stream. It matches coreutils' behavior of printing `cat: dir: Is a directory` and continuing with other operands rather than using the raw EISDIR io::Error text. This keeps output consistent with POSIX cat.","triggerScenarios":"`cat somedir` where `metadata(path)` indicates a directory; the read path detects `FileType::is_dir()` (or maps EISDIR) and returns this variant.","commonSituations":"Glob patterns that expand to include directories (`cat *` in a dir with subdirs); scripts with a variable meant to hold a filename but holding a path; recursive expansions accidentally including directories.","solutions":["Remove the directory from the argument list; cat only regular files.","If you wanted directory contents, use `cat dir/*` (with care for subdirectories) or `find dir -type f -exec cat {} +`.","Tighten globs (e.g. `cat *.txt`) so directories are not matched."],"exampleFix":"// before\n$ cat src/\ncat: src/: Is a directory\n// after\n$ cat src/*.rs","handlingStrategy":"validation","validationCode":"// shell: filter out directories before passing operands to cat\nfiles=()\nfor p in \"$@\"; do\n  [ -f \"$p\" ] && files+=(\"$p\")\ndone\ncat -- \"${files[@]}\"","typeGuard":null,"tryCatchPattern":"// shell: tolerate directory operands in bulk globs\nfor f in *; do\n  [ -f \"$f\" ] && cat -- \"$f\" || true\ndone","preventionTips":["Check -f on every operand when arguments may come from globs or variables.","Tighten glob patterns (e.g. `*.txt` instead of `*`) to exclude directories.","Use `find -type f -exec cat {} +` for recursive concatenation."],"tags":["shell","builtin","filesystem","directory"],"backgroundTag":"is-a-directory","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}