{"record":{"id":"f4cd5e8505395b48","repo":"can1357/oh-my-pi","slug":"not-listing-already-listed-directory","errorCode":null,"errorMessage":"{}: not listing already-listed directory","messagePattern":"(.+?): not listing already-listed directory","errorType":"error_code","errorClass":"LsError","httpStatus":null,"severity":"warning","filePath":"crates/pi-builtins/src/ls.rs","lineNumber":3708,"sourceCode":"\t\t\t} else {\n\t\t\t\tformat!(\"cannot open file {}: Permission denied\", .0.quote())\n\t\t\t},\n\t\t},\n\t\t_ => if 9 == .1.raw_os_error().unwrap_or(1) {\n\t\t\tformat!(\"cannot open directory {}: Bad file descriptor\", .0.quote())\n\t\t} else {\n\t\t\tformat!(\"unknown io error: {}, '{:?}'\", .0.quote(), .1)\n\t\t},\n\t})]\n\tIOErrorContext(PathBuf, std::io::Error, bool, bool),\n\n\t#[error(\"invalid --block-size argument '{0}'\")]\n\tBlockSizeParseError(String),\n\n\t#[error(\"--dired and --zero are incompatible\")]\n\tDiredAndZeroAreIncompatible,\n\n\t#[error(\"{}: not listing already-listed directory\", .0.maybe_quote())]\n\tAlreadyListedError(PathBuf),\n\n\t#[error(\"invalid --time-style argument {}\\nPossible values are:\\n  - [posix-]full-iso\\n  - [posix-]long-iso\\n  - [posix-]iso\\n  - [posix-]locale\\n  - +FORMAT (e.g., +%H:%M) for a 'date'-style format\\n\\nFor more information try --help\", .0.quote())]\n\tTimeStyleParseError(String),\n}\n\nimpl LsError {\n\tfn code(&self) -> i32 {\n\t\tmatch self {\n\t\t\tSelf::InvalidLineWidth(_) => 2,\n\t\t\tSelf::IOError(_) => 1,\n\t\t\tSelf::IOErrorContext(_, _, false, _) => 1,\n\t\t\tSelf::IOErrorContext(_, _, true, _) => 2,\n\t\t\tSelf::BlockSizeParseError(_) => 2,\n\t\t\tSelf::DiredAndZeroAreIncompatible => 2,\n\t\t\tSelf::AlreadyListedError(_) => 2,\n\t\t\tSelf::TimeStyleParseError(_) => 2,\n\t\t}","sourceCodeStart":3690,"sourceCodeEnd":3726,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/crates/pi-builtins/src/ls.rs#L3690-L3726","documentation":"LsError::AlreadyListedError is raised by the builtin `ls` when it encounters a directory argument that has already been listed earlier in the same invocation. GNU-compatible ls deliberately skips duplicate directory arguments to avoid printing the same listing twice (unless -H/--deref-command-line or similar semantics apply).","triggerScenarios":"Passing the same directory twice on the command line, e.g. `ls dir dir`, or `ls . ./` when both resolve to the same directory already listed.","commonSituations":"Shell globs expanding to duplicates (e.g. `ls dir dir/*` where dir matches again), build scripts concatenating directory lists that contain repeats, users repeating a path for emphasis expecting a second listing.","solutions":["Remove the duplicate directory argument from the command line","Deduplicate paths in the script before invoking ls (e.g. `printf '%s\\n' \"$@\" | awk '!seen[$0]++'`)","If repeated listing is genuinely wanted, list them in separate ls invocations","Quote globs carefully so they don't expand to overlapping paths"],"exampleFix":"// before\nls src src\n// after\nls src","handlingStrategy":"validation","validationCode":"const dirs = [...new Set(rawDirs.map(d => resolve(d)))];\nif (dirs.length !== rawDirs.length) {\n  console.warn('duplicate directory arguments removed');\n}","typeGuard":"const hasDuplicatePaths = (paths: string[]): boolean =>\n  new Set(paths.map(p => resolve(p))).size !== paths.length;","tryCatchPattern":"try {\n  runLs(dirs);\n} catch (e) {\n  if (String(e).includes('not listing already-listed directory')) {\n    runLs([...new Set(dirs)]); // dedupe and continue\n  } else throw e;\n}","preventionTips":["Deduplicate directory lists before invoking ls","Expand globs into a Set before building the command","Avoid repeating paths 'for emphasis' — ls skips them","Deduplicate by resolved path, not raw string, to catch ./dir vs dir"],"tags":["cli","duplicate-arguments","ls"],"backgroundTag":"duplicate-argument","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}