can1357/oh-my-pi · warning · LsError

{}: not listing already-listed directory

Error message

{}: not listing already-listed directory

What it means

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).

Source

Thrown at crates/pi-builtins/src/ls.rs:3708

			} else {
				format!("cannot open file {}: Permission denied", .0.quote())
			},
		},
		_ => if 9 == .1.raw_os_error().unwrap_or(1) {
			format!("cannot open directory {}: Bad file descriptor", .0.quote())
		} else {
			format!("unknown io error: {}, '{:?}'", .0.quote(), .1)
		},
	})]
	IOErrorContext(PathBuf, std::io::Error, bool, bool),

	#[error("invalid --block-size argument '{0}'")]
	BlockSizeParseError(String),

	#[error("--dired and --zero are incompatible")]
	DiredAndZeroAreIncompatible,

	#[error("{}: not listing already-listed directory", .0.maybe_quote())]
	AlreadyListedError(PathBuf),

	#[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())]
	TimeStyleParseError(String),
}

impl LsError {
	fn code(&self) -> i32 {
		match self {
			Self::InvalidLineWidth(_) => 2,
			Self::IOError(_) => 1,
			Self::IOErrorContext(_, _, false, _) => 1,
			Self::IOErrorContext(_, _, true, _) => 2,
			Self::BlockSizeParseError(_) => 2,
			Self::DiredAndZeroAreIncompatible => 2,
			Self::AlreadyListedError(_) => 2,
			Self::TimeStyleParseError(_) => 2,
		}

View on GitHub (pinned to 9690622007)

Solutions

  1. Remove the duplicate directory argument from the command line
  2. Deduplicate paths in the script before invoking ls (e.g. `printf '%s\n' "$@" | awk '!seen[$0]++'`)
  3. If repeated listing is genuinely wanted, list them in separate ls invocations
  4. Quote globs carefully so they don't expand to overlapping paths

Example fix

// before
ls src src
// after
ls src
Defensive patterns

Strategy: validation

Validate before calling

const dirs = [...new Set(rawDirs.map(d => resolve(d)))];
if (dirs.length !== rawDirs.length) {
  console.warn('duplicate directory arguments removed');
}

Type guard

const hasDuplicatePaths = (paths: string[]): boolean =>
  new Set(paths.map(p => resolve(p))).size !== paths.length;

Try / catch

try {
  runLs(dirs);
} catch (e) {
  if (String(e).includes('not listing already-listed directory')) {
    runLs([...new Set(dirs)]); // dedupe and continue
  } else throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/f4cd5e8505395b48. Report an issue: GitHub.